diff --git a/.gitignore b/.gitignore index a8347ae..c3584b1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .DS_Store Thumbs.db *.backup +Tools/*.srt +Tools/*.ass diff --git a/Ass/lec3a-chn+eng.ass b/Ass/lec3a-chn+eng.ass index f76ff79..73eb56f 100755 --- a/Ass/lec3a-chn+eng.ass +++ b/Ass/lec3a-chn+eng.ass @@ -1,667 +1,1877 @@ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ -Title: Default Aegisub file +Title: SICP ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal -Scroll Position: 0 -Active Line: 378 -Video Zoom Percent: 1 -PlayResX: 320 -PlayResY: 240 -Audio URI: lec3a.mp4 -Video File: lec3a.mp4 +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: 2344 +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: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,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 +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:18.98,Default,,0,0,0,,[MUSIC PLAYING] -Dialogue: 0,0:00:20.94,0:00:23.86,Default,,0,0,0,,好 上次我们讨论了组和数据\NPROFESSOR: Well, last time we talked about compound data, -Dialogue: 0,0:00:24.70,0:00:29.74,Default,,0,0,0,,还举了两个示例\Nand there were two main points to that business. -Dialogue: 0,0:00:29.74,0:00:32.48,Default,,0,0,0,,首先 有一种数据抽象的方法\NFirst of all, there was a methodology of data abstraction, -Dialogue: 0,0:00:32.48,0:00:41.48,Default,,0,0,0,,(这个思想的)关键是分离使用的数据对象和数据对象的表示(的意义)\Nand the point of that was that you could isolate the way that data objects are used from the way that they're represented: -Dialogue: 0,0:00:41.48,0:00:45.20,Default,,0,0,0,,这个想法 -- 大家要跟George这个家伙联系一下\Nthis 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,Default,,0,0,0,,他负责数据对象的表示\Nand it's his business to represent the data objects; -Dialogue: 0,0:00:47.48,0:00:49.36,Default,,0,0,0,,于此同时 大家使用这些(表示)\Nand at the moment you are using them, -Dialogue: 0,0:00:49.36,0:00:51.36,Default,,0,0,0,,大家并不需要关心(实现那是)George的问题\Nyou don't think about George's problem. -Dialogue: 0,0:00:51.98,0:01:00.52,Default,,0,0,0,,其次 在Lisp中有一种特殊的方式把对象连接在一起,它是pairs #TBD 我不知道pair应该如何翻译,整个字幕都没有翻译它\NAnd then secondly, there was this particular way that Lisp has of gluing together things to form objects called pairs, -Dialogue: 0,0:01:00.52,0:01:03.54,Default,,0,0,0,,它用cons car cdr实现\Nand that's done with cons, car and cdr. -Dialogue: 0,0:01:03.54,0:01:07.16,Default,,0,0,0,,cons car cdr都是独立实现的(没有依赖)\NAnd the way that cons, car and cdr are implemented is basically irrelevant. -Dialogue: 0,0:01:07.16,0:01:10.02,Default,,0,0,0,,George的问题就是如何构建这些东西\NThat's sort of George's problem of how to build those things. -Dialogue: 0,0:01:10.02,0:01:11.16,Default,,0,0,0,,可以把他们当作基元(基本元素)来实现\NIt could be done as primitives. -Dialogue: 0,0:01:11.16,0:01:13.80,Default,,0,0,0,,他们也可以使用过程实现 虽然这种方式有点古怪\NIt could be done using procedures in some weird way, -Dialogue: 0,0:01:13.80,0:01:15.36,Default,,0,0,0,,但是不用我们操心这些\Nbut we're not going to worry about that. -Dialogue: 0,0:01:16.02,0:01:19.66,Default,,0,0,0,,作为一个例子 我们看一下实数运算.\NAnd as an example, we looked at rational number arithmetic. -Dialogue: 0,0:01:19.66,0:01:21.50,Default,,0,0,0,,我们看一下向量\NWe looked at vectors, -Dialogue: 0,0:01:21.50,0:01:24.18,Default,,0,0,0,,这里简单回顾一下向量\Nand here's just a review of vectors. -Dialogue: 0,0:01:24.18,0:01:27.64,Default,,0,0,0,,这里有个对两个向量求和的操作符\NHere's an operation that takes the sum of of two vectors, -Dialogue: 0,0:01:27.64,0:01:33.32,Default,,0,0,0,,我们想要把向量v1和v2相加求和\Nso 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,Default,,0,0,0,,和也是一个向量 它的坐标是两个向量的坐标的和\NAnd 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,Default,,0,0,0,,我定义make-vect求两个向量的和\NSo I can say, to define make-vect, right, to add two vectors -Dialogue: 0,0:01:45.66,0:01:51.72,Default,,0,0,0,,我创建一个向量 x坐标是两个向量x坐标的和\NI make a vector, whose x coordinate is the sum of the two x coordinates, -Dialogue: 0,0:01:52.10,0:01:54.82,Default,,0,0,0,,(这个向量的)y坐标是两个向量y坐标的和\Nand whose y coordinate is the sum of the two y coordinates. -Dialogue: 0,0:01:56.06,0:02:04.10,Default,,0,0,0,,同样 我们也可以定义一个缩放向量的操作\NAnd then similarly, we could have an operation that scales vectors, -Dialogue: 0,0:02:04.94,0:02:12.66,Default,,0,0,0,,这里有一个缩放的过程 用数字s乘以向量v\Nso here's a procedure scale that multiplies a vector, v, by some number, s. -Dialogue: 0,0:02:13.08,0:02:20.24,Default,,0,0,0,,这个是v v从这里到这里 我放大了v 这个向量跟v方向相同 只是更长了\NSo 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. -Dialogue: 0,0:02:21.56,0:02:24.26,Default,,0,0,0,,要缩放向量 需要(用s)乘向量坐标\NAnd again, to scale a vector, I multiply the successive coordinates. -Dialogue: 0,0:02:24.26,0:02:30.22,Default,,0,0,0,,所以我创建了一个向量 它的x坐标是原来向量x坐标的缩放倍数(s倍)\NSo 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,Default,,0,0,0,,同时 它的y坐标是原来向量y坐标的缩放倍数(s倍)\Nand whose y coordinate is the scale factor times the y coordinate. -Dialogue: 0,0:02:33.54,0:02:40.28,Default,,0,0,0,,所以这里实现了两个操作符用来表示(代表)向量\NSo those are two operations that are implemented using the representation of vectors. -Dialogue: 0,0:02:40.28,0:02:45.02,Default,,0,0,0,,这种向量的表示方法,我们可以依据pairs来实现。\NAnd the representation of vectors, for instance, is something that we can build\Nin terms of pairs. -Dialogue: 0,0:02:45.34,0:02:51.28,Default,,0,0,0,,所以George实现了make-vector x坐标 y坐标 为我们使用#TBD may be these all funtion name\NSo 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,Default,,0,0,0,,他可以使用cons car cdr来实现(这三个函数)\Nand this could be done, for instance, using cons,car and cdr; -Dialogue: 0,0:02:58.88,0:03:06.78,Default,,0,0,0,,但是注意 我这里写了一个完全不同的方式\Nand notice here, I wrote this in a slightly different way. -Dialogue: 0,0:03:08.04,0:03:16.22,Default,,0,0,0,,这个过程我们之前看过(make-vector x y (cons x y)) #TBD maybe right \NThe procedures we've seen before, I've said something like say, make-vector of x and y: cons of x and y. -Dialogue: 0,0:03:16.22,0:03:17.98,Default,,0,0,0,,这里我只写了make-vector cons\NAnd here I just wrote make-vector cons. -Dialogue: 0,0:03:17.98,0:03:20.48,Default,,0,0,0,,这表示他们完全不同\NAnd that means something slightly different. -Dialogue: 0,0:03:20.48,0:03:26.22,Default,,0,0,0,,之前我们说 定义make-vector过程用两个参数x y\NPreviously 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,Default,,0,0,0,,并且用cons把x y连接在一起\Nand does cons of x and y. -Dialogue: 0,0:03:28.04,0:03:34.12,Default,,0,0,0,,这里需要说的是 用cons来定义make-vector是因为\NAnd here I am saying define make-vector to be the thing that cons is, -Dialogue: 0,0:03:35.18,0:03:39.66,Default,,0,0,0,,这跟其他我们写的代码的方式差不多\Nand that's almost the same as the other way we've been writing things. -Dialogue: 0,0:03:39.66,0:03:46.58,Default,,0,0,0,,大家需要习惯过程也是对象 并且它可以命名(来使用)这种思想\NAnd I just want you to get used to the idea that procedures can be objects, and\Nthat you can name them. -Dialogue: 0,0:03:48.70,0:03:51.80,Default,,0,0,0,,这代表一个向量\NOK, well there's vector representation, and again, -Dialogue: 0,0:03:51.80,0:03:55.68,Default,,0,0,0,,但如果我要说的就仅仅是这些 那就太无聊了\Nif that was all there was to it,this would all be pretty boring. -Dialogue: 0,0:03:57.02,0:04:02.16,Default,,0,0,0,,重点是 要记住 大家可以用cons连接不仅仅是pair中的数字\NAnd 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,Default,,0,0,0,,它可以连接任何东西\Nbut to glue together arbitrary things. -Dialogue: 0,0:04:05.20,0:04:11.60,Default,,0,0,0,,例如 如果我想表示一个线段\NSo for instance, if we'd like to represent a line segment, -Dialogue: 0,0:04:11.60,0:04:16.06,Default,,0,0,0,,可以说 线段来自一个特定的向量\Nsay the line segment that goes from a certain vector: say, -Dialogue: 0,0:04:16.06,0:04:28.30,Default,,0,0,0,,这个线段从向量(2,3)的端点开始到向量(5,1)的端点\Nthe 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,Default,,0,0,0,,如果我们想表示这条线段\NIf we want to represent that line segment, -Dialogue: 0,0:04:33.26,0:04:36.20,Default,,0,0,0,,那么我们可以构建一个pair的pair\Nthen we can build that as a pair of pairs. -Dialogue: 0,0:04:40.72,0:04:42.94,Default,,0,0,0,,这样我们就可以表示一个线段了\NSo again, we can represent line segments. -Dialogue: 0,0:04:42.94,0:04:47.34,Default,,0,0,0,,我们可以做一个构造器 使用cons构造线段\NWe can make a constructor that makes a segment using cons, -Dialogue: 0,0:04:47.34,0:04:51.60,Default,,0,0,0,,选择线段的起始点 选择线段的终止点\Nselects out the start of a segment, selects out the end point of the segment; -Dialogue: 0,0:04:55.00,0:05:02.10,Default,,0,0,0,,实际上 如果撇开抽象层不管 我们可以说 这个(线段)就是pair的pair\Nand 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, -Dialogue: 0,0:05:04.66,0:05:06.22,Default,,0,0,0,,我们还称它是一个pair\Nwe'd say well that's a pair. -Dialogue: 0,0:05:06.22,0:05:08.22,Default,,0,0,0,,这就是一个线段\NHere's the segment. -Dialogue: 0,0:05:10.00,0:05:16.72,Default,,0,0,0,,这个线段的car是一个pair 它的cdr也是一个pair\NIt'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,Default,,0,0,0,,它的car是一个pair--(2,3)\Nand then what the car is--here's the car, that itself is a pair of 2 and 3. -Dialogue: 0,0:05:25.90,0:05:27.92,Default,,0,0,0,,cdr是pair(2,3)\NAnd similarly the cdr is a pair of 2 and 3. -Dialogue: 0,0:05:27.92,0:05:36.98,Default,,0,0,0,,我再次提醒大家一次 好多人认为如果我画的这个箭头是向下的,有其它的含意\NAnd 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. -Dialogue: 0,0:05:36.98,0:05:38.28,Default,,0,0,0,,这个是不对的(箭头的指向毫无关系)\NThat's irrelevant. -Dialogue: 0,0:05:38.28,0:05:43.90,Default,,0,0,0,,这个仅仅是这些(对象)是如何连接的,与箭头的水平还是竖直没有关系。\NIt'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,Default,,0,0,0,,还要提醒一下,这个(pair)概念是闭包。(数学概念)\NAnd again just to remind you, there was this notion of closure. -Dialogue: 0,0:05:52.94,0:06:05.62,Default,,0,0,0,,看,闭包可以让我们构建更复杂的事情,不必陷入pair细节\NSee, 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,Default,,0,0,0,,特别的,我说的事情就是我们正在做的---使用cons构造一个pair\NParticularly 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,Default,,0,0,0,,pair中的元素,也可以用cons来构造。这样可以构造出更加复杂的东西。\Nthose things themselves can be combined using cons to make\Nmore complicated things. -Dialogue: 0,0:06:23.28,0:06:31.98,Default,,0,0,0,,数学家可能会说,在lisp中的数据集合在pair构造的操作中是封闭的.\NOr 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,Default,,0,0,0,,这就允许我们做更加复杂的构造\NThat's the thing that allows us to build complexity. -Dialogue: 0,0:06:36.34,0:06:42.46,Default,,0,0,0,,这个很显然,但是要记住,很多人们使用的计算机语言不是封闭的\NAnd that seems obvious, but remember, a lot of the things in the computer languages that people use are not closed. -Dialogue: 0,0:06:42.46,0:06:52.18,Default,,0,0,0,,举例来说,数组很基本,但是在Fortran中就不是封闭的操作,大家可以创建数字,字符串或者别的什么数组\NSo 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, -Dialogue: 0,0:06:52.18,0:06:54.18,Default,,0,0,0,,但是大家不能创建数组的数组\Nbut you can't make an array of arrays. -Dialogue: 0,0:06:54.64,0:07:02.78,Default,,0,0,0,,在对待组合的意义时 大家应该问自己在这种组合下是否是封闭的\NAnd when you look at means of combination, you should be should be asking yourself whether things are closed under that means of combination. -Dialogue: 0,0:07:05.06,0:07:12.92,Default,,0,0,0,,在任何情况下 因为我们可以构造pair的pair 我们可以使用各种各样的方式把对象连接起来 \NWell in any case, because we can form pairs of pairs, 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,Default,,0,0,0,,比如我要连接四个数 -- 1,2,3,4\NSo 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,Default,,0,0,0,,我有很多方式可以做\Nthere are a lot of ways I can do it. -Dialogue: 0,0:07:20.66,0:07:36.88,Default,,0,0,0,,比如,像我们做的线段 我可以构造一个pair 它是((1 2) (3 4)) 对吧\NI 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? -Dialogue: 0,0:07:36.88,0:07:40.06,Default,,0,0,0,,如果我喜欢 我可以像这样做\NOr if I liked, I could do something like this. -Dialogue: 0,0:07:40.06,0:07:55.08,Default,,0,0,0,,我可以构造一个pair 它的第一个元素是pair 这个pair的car是1 它的cdr是一个pair (2 3) 我把4放在这里\NI 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. -Dialogue: 0,0:07:56.92,0:08:02.16,Default,,0,0,0,,大家看 把对象连接起来的方式有很多种\NSo 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,Default,,0,0,0,,所以有必要建立一些方便(的方式)\Nand so it'll be a good idea to establish some kind of conventions,right, -Dialogue: 0,0:08:07.74,0:08:11.58,Default,,0,0,0,,这样我们就可以用一些便捷的方式处理数据\Nthat allow us to deal with this thing in some conventional way, -Dialogue: 0,0:08:11.58,0:08:14.00,Default,,0,0,0,,这样我们就不用总是做一些选择\Nso we're not constantly making an ad hoc choice. -Dialogue: 0,0:08:15.86,0:08:25.82,Default,,0,0,0,,列表非常方便的表示一个序列 如pair链\NAnd List has a particular convention for representing a sequence of things as, essentially, a chain of pairs, -Dialogue: 0,0:08:26.78,0:08:28.18,Default,,0,0,0,,这个就叫做列表\Nand that's called a List. -Dialogue: 0,0:08:34.72,0:08:40.50,Default,,0,0,0,,列表的本质其实就是代表序列的便捷方式\NAnd what a List is is essentially just a convention for representing a sequence. -Dialogue: 0,0:08:40.70,0:08:47.38,Default,,0,0,0,,我可以使用pair的序列来表示序列 1,2,3,4\NI would represent the sequence 1, 2, 3 and 4 by a sequence of pairs. -Dialogue: 0,0:08:48.26,0:09:01.52,Default,,0,0,0,,我把1放在这里 它的cdr指向另一个pair 这个pair的car是序列的下一个数(这里说的是2)\NI'd put 1 here and then the cdr of this would point to another pair whose car was the next thing in the sequence, -Dialogue: 0,0:09:01.52,0:09:07.26,Default,,0,0,0,,并且它的cdr指向了另一个pair 它的car是序列的再下一个数\Nand the cdr would point to another pair whose car was the next thing in the sequence-- -Dialogue: 0,0:09:07.26,0:09:08.44,Default,,0,0,0,,这个是数是3\Nso there's 3-- -Dialogue: 0,0:09:08.44,0:09:09.74,Default,,0,0,0,,以此类推\Nand then another one. -Dialogue: 0,0:09:09.74,0:09:13.22,Default,,0,0,0,,所以 对于序列中的每一个元素 都是一个pair\NSo for each item in the sequence, I'll get a pair. -Dialogue: 0,0:09:15.54,0:09:22.56,Default,,0,0,0,,现在这个序列中没有更多元素了 我用一个特殊的标记表示列表中没有元素了 \NAnd now there are no more, so I put a special marker that means there's nothing more in the List. -Dialogue: 0,0:09:24.14,0:09:34.64,Default,,0,0,0,,好 所以这是一种非常方便的方式将序列中的元素连接在一起\NOK, 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:44.84,Default,,0,0,0,,它其实就是一大堆pair 每个pair中的car就是大家想要连接到一起的元素\NAnd what it is is a bunch of pairs, 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,Default,,0,0,0,,cdr指向的是下一个pair指针\Nand the cdr pointer points to the next pair. -Dialogue: 0,0:09:50.02,0:09:56.04,Default,,0,0,0,,现在如果我真的想要构造它 我需要向Lisp中输入:\NNow if I actually wanted to construct that, what I would type into Lisp is this: -Dialogue: 0,0:09:56.04,0:09:58.72,Default,,0,0,0,,就像是我说的那样构造\NI'd actually construct that as saying, -Dialogue: 0,0:09:58.72,0:10:15.28,Default,,0,0,0,,(cons 1 (cons 2 (cons 3 (cons 4 nil))))\Nwell this thing is the cons of 1 onto the cons of 2 onto the cons of 3 onto\Nthe cons of 4 onto, well, this thing nil. -Dialogue: 0,0:10:15.28,0:10:20.00,Default,,0,0,0,,nil是列表结束的标记符号\NAnd what nil is is a name for the end of List marker. -Dialogue: 0,0:10:20.80,0:10:23.82,Default,,0,0,0,,它是一个特殊的名字 意味着列表结束了\NIt's a special name, which means this is the end of the List. -Dialogue: 0,0:10:26.24,0:10:30.26,Default,,0,0,0,,这就是我如何构造列表\NOK, so that's how I would actually construct that. -Dialogue: 0,0:10:37.34,0:10:45.18,Default,,0,0,0,,当然 构造列表的时候总是写cons非常费力\NOf 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. -Dialogue: 0,0:10:45.18,0:10:57.72,Default,,0,0,0,,所以列表有一个操作叫做list list其实是这种cons递归结构的缩写\NSo List has an operation that's called List, and List is just an abbreviation for this nest of conses. -Dialogue: 0,0:10:57.72,0:11:06.32,Default,,0,0,0,,所以我可以说 我构造列表(list 1 2 3 4)\NSo 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:14.76,Default,,0,0,0,,所有的这些是一个语法糖 它是一串cons序列的缩写\NAnd all this is is another way, a piece of syntactic sugar, a more convenient way for writing that chain of conses-- -Dialogue: 0,0:11:14.76,0:11:17.84,Default,,0,0,0,,(这个序列是)cons的cons的cons的cons\Ncons of cons of cons of cons of cons of cons onto nil. -Dialogue: 0,0:11:18.48,0:11:39.78,Default,,0,0,0,,举例来说 我将定义列表(1 2 3 4)叫做1-TO-4\NSo for example, I could build this thing and say, I'll define 1-TO-4 to be the\NList of 1, 2, 3 and 4. -Dialogue: 0,0:11:47.96,0:11:53.02,Default,,0,0,0,,注意使用这种便捷写法的后果\NOK, well notice some of the consequences of using this convention. -Dialogue: 0,0:11:53.60,0:12:00.26,Default,,0,0,0,,首先 如果我有这个列表(1 2 3 4) 那么 列表的car就是这个列表的第一个元素\NFirst 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. -Dialogue: 0,0:12:01.90,0:12:05.28,Default,,0,0,0,,那么,我们如何获得元素2呢?\NHow do I get 2? -Dialogue: 0,0:12:05.28,0:12:23.10,Default,,0,0,0,,2应该是1-TO-4的cdr的car\NWell, 2 would be the car of the cdr of this thing 1-TO-4, it would be 2, right. -Dialogue: 0,0:12:23.46,0:12:29.48,Default,,0,0,0,,它的cdr是这个\NI take this thing, I take the cdr of it, which is this much, -Dialogue: 0,0:12:29.82,0:12:31.68,Default,,0,0,0,,而它的car是2.\Nand the car of that is 2, -Dialogue: 0,0:12:32.58,0:12:47.42,Default,,0,0,0,,同理 1-TO-4的cdr的cdr的car\Nand 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,Default,,0,0,0,,是3 以此类推\Nwould give me 3, and so on. -Dialogue: 0,0:12:52.68,0:12:55.84,Default,,0,0,0,,我们看一下电脑屏幕\NLet's take a look at that on the computer screen for a second. -Dialogue: 0,0:12:57.50,0:13:11.18,Default,,0,0,0,,我定义一个列表(1 2 3 4)叫它1-TO-4\NI 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,Default,,0,0,0,,我这样写 计算机返回定义完成 这个就是1-TO-4的定义\NAnd I'll tell that to List, and it says, fine, that's the definition of 1-TO-4. -Dialogue: 0,0:13:22.30,0:13:36.74,Default,,0,0,0,,我问 比如 1-TO-4的cdr的cdr的car\NAnd 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,Default,,0,0,0,,嗯 它是3\NRight, so the car of the cdr of the cdr would be 3. -Dialogue: 0,0:13:44.08,0:13:50.08,Default,,0,0,0,,或者我问 1-TO-4是什么\NRight, or I could say, what's 1-TO-4 itself. -Dialogue: 0,0:13:51.26,0:13:57.22,Default,,0,0,0,,大家可以看到列表输出的是(1 2 3 4) (结果)用括号包围着\NAnd you see what List typed out is 1, 2, 3, 4, enclosed in parentheses, -Dialogue: 0,0:13:57.22,0:14:02.12,Default,,0,0,0,,这是一个标记 用括号将列表中的元素包围起来\Nand this notation, typing the elements of the List enclosed in parentheses -Dialogue: 0,0:14:02.12,0:14:08.90,Default,,0,0,0,,是打印用pair构造出来的序列的一种传统方式\Nis List's conventional way for printing back this chain of pairs that represents a sequence. -Dialogue: 0,0:14:08.90,0:14:17.14,Default,,0,0,0,,又比如 我问1-TO-4的cdr是什么\NSo for example, if I said, what's the cdr of 1-TO-4, -Dialogue: 0,0:14:19.30,0:14:21.12,Default,,0,0,0,,那是列表的剩余元素(除去1之外)\Nthat's going to be the rest of the List. -Dialogue: 0,0:14:21.32,0:14:26.96,Default,,0,0,0,,它是列表的第一个pair指向的子序列 这个序列开始于2\NThat'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:44.82,Default,,0,0,0,,比如 1-TO-4的cdr的cdr是什么 返回(3 4)\NOr for example, I go off and say, what's the cdr of the cdr of 1-TO-4; then that's 3,4. -Dialogue: 0,0:14:44.82,0:14:59.66,Default,,0,0,0,,或者 1-TO-4的cdr的cdr的cdr的cdr是什么\NOr 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,Default,,0,0,0,,我们看一下列表的尾指针 列表打印结果是()\Nand I'm down there looking at the end of List pointer itself, and List prints that as just open paren, close paren. -Dialogue: 0,0:15:10.68,0:15:13.76,Default,,0,0,0,,大家可以看到列表中什么东西都没有\NYou can think of that as a List with nothing in there. -Dialogue: 0,0:15:13.76,0:15:25.20,Default,,0,0,0,,1-TO-4的cdr的cdr的cdr的末尾(的打印结果) 是列表的尾指针它本身\NAll 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. -Dialogue: 0,0:15:25.20,0:15:27.20,Default,,0,0,0,,它的输出是()\NAnd that gets printed as open close. -Dialogue: 0,0:15:34.14,0:15:43.44,Default,,0,0,0,,大家看到的用序列的cdr来操作列表是非常常见的方式\NAll right, well that's a conventional way you can see for working down a List by taking successive cdrs of things. -Dialogue: 0,0:15:43.44,0:15:45.44,Default,,0,0,0,,这个叫做列表的cdring\NIt's called cdring down a List. -Dialogue: 0,0:15:46.64,0:15:49.78,Default,,0,0,0,,当然手写这些cdr非常费劲\NAnd 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,Default,,0,0,0,,大家没有必要这么做\NYou don't do that. 可以写一个过程来做这些。\NYou write procedures that do that. -Dialogue: 0,0:15:52.96,0:15:59.10,Default,,0,0,0,,事实上 Lisp中非常普遍的事情是写一些过程\NAnd in fact one very, very common thing to do in Lisp is to write procedures that, sort of, -Dialogue: 0,0:15:59.10,0:16:06.54,Default,,0,0,0,,过程使用列表 对列表的每一个元素进行一些操作 并返回结果列表\Ntake 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.28,0:16:11.92,Default,,0,0,0,,比如 我写一个过程叫做scale-list\NSo what I mean for example, is I might write a procedure called Scale-List, -Dialogue: 0,0:16:16.80,0:16:35.32,Default,,0,0,0,,我要用scale-list将列表1-TO-4放大10倍 那么它应该返回列表(10 20 30 40)\Nand 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. -Dialogue: 0,0:16:35.32,0:16:37.66,Default,,0,0,0,,不详\N[UNINTELLIGIBLE PHRASE] -Dialogue: 0,0:16:38.20,0:16:49.30,Default,,0,0,0,,没错 它返回一个列表 大家可以看到这里可以使用了一些递归策略来做处理\NRight, it returns List, and well you can see that there's going to be some kind\Nof recursive strategy for doing it. -Dialogue: 0,0:16:49.30,0:16:51.30,Default,,0,0,0,,我应该如何写这个过程呢?\NHow would I actually write that procedure? -Dialogue: 0,0:16:52.52,0:16:59.80,Default,,0,0,0,,这个想法是:如果要构建一个每个元素都乘以10的列表\NThe 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:08.42,Default,,0,0,0,,需要做的是--假设已经得到了结果列表的剩余元素--也就是列表的cdr\Nwhat you'd say is well you imagine that you'd taken the rest of the List--\Nright, the thing represented by the cdr of the List, -Dialogue: 0,0:17:08.42,0:17:14.16,Default,,0,0,0,,这个子列表中的每个元素都是原来的元素乘以10\Nand 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,Default,,0,0,0,,这是scale-list对列表cdr作用的结果\Nthat would be Scale-List of the cdr of the List. -Dialogue: 0,0:17:20.12,0:17:27.30,Default,,0,0,0,,我需要做的事情就只有用列表的car乘以10 然后用cons将它和剩余部分连接起来 返回这个列表。\NAnd 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. -Dialogue: 0,0:17:28.78,0:17:36.42,Default,,0,0,0,,以此递归 缩放列表的cdr 我将缩放它(列表的cdr)的cdr 并且用2*10跟它连接起来\NRight 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. -Dialogue: 0,0:17:36.42,0:17:41.16,Default,,0,0,0,,最终 当我处理到列表的结尾的时候 我有列表的尾指针\NAnd finally when I get all the way down to the end, and I only have this end\Nof List pointer. -Dialogue: 0,0:17:41.72,0:17:45.28,Default,,0,0,0,,对,它叫做nil 我就直接返回列表尾指针\NAll right, this thing whose name is nil-- well I just returned an end of\NList pointer. -Dialogue: 0,0:17:45.54,0:17:47.68,Default,,0,0,0,,所以这就是这个过程的递归策略\NSo there's a recursive strategy for doing that. -Dialogue: 0,0:17:47.68,0:17:50.52,Default,,0,0,0,,这个过程就是这样\NHere's the actual procedure that does that. -Dialogue: 0,0:17:50.96,0:17:58.24,Default,,0,0,0,,这就是使用cdr向下处理列表 用cons反向连接结果的总体策略\NRight, this is an example of the general strategy of cdr-ing down a List and\Nso called cons-ing up the result, right. -Dialogue: 0,0:17:58.24,0:18:06.04,Default,,0,0,0,,然后 对列表l进行缩放因子s的处理应该如何做呢?\NSo to Scale a List l by some scale factor s, what do I do? -Dialogue: 0,0:18:06.04,0:18:10.40,Default,,0,0,0,,这里有个判断 列表有个判断叫做null\NWell there's a test, and List has the predicate called null. -Dialogue: 0,0:18:10.40,0:18:17.56,Default,,0,0,0,,null意思是这是列表的结尾 或者列表中还有元素\NNull 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. -Dialogue: 0,0:18:17.56,0:18:23.00,Default,,0,0,0,,但是在任何情况下 如果我找列表的尾指针 那么就返回给我列表的尾指针\NBut 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.00,0:18:35.14,Default,,0,0,0,,我就是简单的返回nil 其他情况我用cons把列表中的第一个元素个我还需要处理的子列表连接起来 #TBD 这两句话需要重新考虑一下\NI just return nil, 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:46.34,Default,,0,0,0,,就是说 我取l的car然后用它乘以s 然后我用cons递归连接正在缩放的剩余的列表\Nnamely taking the car of l and multiplying it by s, and I cons that onto recursively scaling the rest of the List. -Dialogue: 0,0:18:49.80,0:18:56.48,Default,,0,0,0,,再说一次 总体的思想是用cdr递归的处理列表的剩余元素\NOK, so again, the general idea is that 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,Default,,0,0,0,,然后用cons把列表的第一个元素的处理结果跟剩余元素连接起来\Nand then you cons that onto actually doing something to the first element of the List. -Dialogue: 0,0:19:01.16,0:19:11.36,Default,,0,0,0,,当你向后处理到结尾的时候 返回列表的尾指针 这是一个处理列表的基本模式\NWhen 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. -Dialogue: 0,0:19:16.14,0:19:22.62,Default,,0,0,0,,当然有一个通用的模式可以省去我写这个过程\NWell 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. -Dialogue: 0,0:19:22.62,0:19:24.90,Default,,0,0,0,,我要做的事情就是写一个过程\NWhat I should do is write a procedure -Dialogue: 0,0:19:24.90,0:19:30.42,Default,,0,0,0,,这是一个通用模式 为列表的每一个元素做一些依据定义所做的事情\Nthat's the general pattern itself that says, do something to everything in the List and define this thing in terms of that. -Dialogue: 0,0:19:30.42,0:19:35.18,Default,,0,0,0,,对,创建了一个高阶过程 这就是我说的那个高阶过程 它叫做map\NRight, make some higher order procedure, and here's the higher order procedure that does that.It's called MAP, -Dialogue: 0,0:19:36.58,0:19:43.60,Default,,0,0,0,,map可以处理列表 把列表l传入 并且传入一个过程p\Nand what MAP does is it takes a List, takes a List l, and it takes a procedure p, -Dialogue: 0,0:19:44.64,0:19:51.26,Default,,0,0,0,,然后它返回一个列表 列表中的每个元素都被过程p所应用(apply)\Nand it returns the List of the elements gotten by applying p to each successive element in the List. -Dialogue: 0,0:19:51.80,0:19:55.64,Default,,0,0,0,,对(p v1) (p v2) 等等\NAll right, so p to v1, p to v2, p of en. -Dialogue: 0,0:19:55.64,0:20:01.54,Default,,0,0,0,,我想说的是它把一个列表的每一个元素用p进行了转化\NRight, 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,Default,,0,0,0,,大家看到的这个过程是一个非常通用的策略 正如我上面提到的\NAnd you see all this procedure is is exactly the general strategy I said. -Dialogue: 0,0:20:07.08,0:20:09.08,Default,,0,0,0,,我们用它写乘以10的过程\NInstead of multiply by 10, it's do the procedure. -Dialogue: 0,0:20:09.08,0:20:11.86,Default,,0,0,0,,如果列表是空的 返回nil\NIf the List is empty,return nil. -Dialogue: 0,0:20:11.86,0:20:16.60,Default,,0,0,0,,否则 对列表的第一个元素应用p\NOtherwise, apply p to the first element of the List. -Dialogue: 0,0:20:17.04,0:20:25.40,Default,,0,0,0,,对(p (car l)) 然后连接它和列表中其他将要应用p的子列表--列表的cdr\NRight, apply p to car of l, and cons that onto the result of applying p to everything in the cdr of the List, -Dialogue: 0,0:20:25.40,0:20:29.06,Default,,0,0,0,,这个通用的过程叫做map\Nso that's a general procedure called MAP. -Dialogue: 0,0:20:29.06,0:20:39.04,Default,,0,0,0,,我们可以依据map来定义scale-list\NAnd I could define Scale-List in terms of MAP. -Dialogue: 0,0:20:39.04,0:20:41.04,Default,,0,0,0,,我给大家展示一下\NLet me show you that first. -Dialogue: 0,0:20:43.46,0:20:52.50,Default,,0,0,0,,scale-list仅仅是map这个列表和一个过程的的命名\NBut 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,Default,,0,0,0,,这个过程需要一个参数 返回给定参数乘以s的结果\Nwhich takes an item and multiplies it by s. -Dialogue: 0,0:20:58.78,0:21:07.40,Default,,0,0,0,,这就是我缩放列表的真实想法 构建一个递归到这个通用策略中 省去我为每一个过程都要写(一个框架)\NRight, 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. -Dialogue: 0,0:21:07.40,0:21:11.70,Default,,0,0,0,,当然,这样做的意义之一是 看到了其中的共性\NAnd 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,Default,,0,0,0,,大家正在掌握使用通用模式\NRight, again you're capturing general patterns of usage. -Dialogue: 0,0:21:15.96,0:21:31.18,Default,,0,0,0,,比如,求列表的平方 我给map传递一个平方过程 列表1-TO-4 然后它返回给我的是(1 4 9 16)\NFor 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:58.56,Default,,0,0,0,,我说 map这个列表(lambda (x) (+ x 10))如果我对1-TO-4应用这个map 列表的每一个元素都增加了10 那么结果是(11 12 13 14)\NRight, or if I said MAP down this List, lambda of x plus x 10, 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. -Dialogue: 0,0:22:00.56,0:22:05.76,Default,,0,0,0,,大家可以看到一个非常非常通用的想法:对列表的每一个元素进行一些处理\NAnd 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,Default,,0,0,0,,大家需要做的只是构建map的递归模式\NOne thing you might think about is writing MAP in an iterative style. -Dialogue: 0,0:22:12.22,0:22:19.10,Default,,0,0,0,,我写的恰巧是一个递归的演化版本 但是我们也可以很容易的把它改成迭代过程\NThe one I wrote happens to evolve a recursive process, but we could just as easily have made one that evolves an iterative process. -Dialogue: 0,0:22:19.10,0:22:23.40,Default,,0,0,0,,有趣的事情是 一旦大家开始用map来思考\NBut 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,Default,,0,0,0,,比如 一旦说缩放仅仅是一个map 而不在考虑map是迭代还是递归\Nsee, 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,Default,,0,0,0,,你可以说 有这样一种策略 给定这个列表\Nand you just say, well there's this aggregate, there's this List, -Dialogue: 0,0:22:32.22,0:22:38.36,Default,,0,0,0,,要做的事情就是对列表的每一个元素进行转化 它使我不用去考虑特别的控制流程\Nand what I do is transform every item in the List, and I stop thinking about the particular control structure in order. -Dialogue: 0,0:22:38.88,0:22:46.48,Default,,0,0,0,,这是非常非常重要的想法 我猜这个想法来自APL\NThat's a very, very important idea, and it, I guess it really comes out of APL. -Dialogue: 0,0:22:46.48,0:22:53.92,Default,,0,0,0,,这个是APL中非常重要的思想:不要去想控制结构 让你关注于策略操作\NIt's, sort of, the really important idea in APL that you stop thinking about control structures, and you start thinking about operations on aggregates, -Dialogue: 0,0:22:54.80,0:23:02.64,Default,,0,0,0,,在课程一半的时候 我们将讨论叫做流过程的事情 用那个视角看世界是那么的美丽\Nand 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. -Dialogue: 0,0:23:02.64,0:23:05.30,Default,,0,0,0,,这个是一种很聪明的思想\NThis is just us a, sort of, cute idea. -Dialogue: 0,0:23:05.30,0:23:08.70,Default,,0,0,0,,我们可以在以后看到更过的应用\NBut we'll see much more applications of that later on. -Dialogue: 0,0:23:09.36,0:23:16.84,Default,,0,0,0,,还有一些非常有用的过程也非常像map\NWell 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:25.62,Default,,0,0,0,,map可以说是 给我一个列表 map对每一个元素进行应用 然后返回相应的值的一个列表\Nsee, MAP says I take a List, I apply something to each item, and I return a List of the successive values. -Dialogue: 0,0:23:25.98,0:23:36.18,Default,,0,0,0,,我还想做一些其他事情 和这个非常非常相似 它是给定一个列表 一些想要的(操作)行为 然后对序列的每一个元素都进行处理\NThere'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. -Dialogue: 0,0:23:36.18,0:23:45.10,Default,,0,0,0,,这不是创建一个新的列表 仅仅是做一些特殊的操作 这个过程非常像map\NDon't make a List of the values, just do this particular action, and that's something that's\Nvery much like MAP. -Dialogue: 0,0:23:45.10,0:23:54.38,Default,,0,0,0,,这个称作for-each 它需要一个过程和一个列表 它要做的事情就是对每一个元素应用(传入的过程)\NIt'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. -Dialogue: 0,0:23:54.38,0:24:11.84,Default,,0,0,0,,通常它会:如果列表不是空的 我应用这个过程到列表的第一个元素 然后对列表的剩余元素做同样的事情\NSo basically what it does: it says if the 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. -Dialogue: 0,0:24:12.30,0:24:15.34,Default,,0,0,0,,(for-each (cdr l))\NI apply for-each to the cdr of the List. -Dialogue: 0,0:24:15.34,0:24:18.82,Default,,0,0,0,,对,我对列表的第一个元素进行处理 然后对列表的剩余元素进行处理\NAll 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,Default,,0,0,0,,当然 当我使用递归时 这讲对列表的剩余列表的剩余列表进行处理 依次类推\Nand 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:32.40,Default,,0,0,0,,最终 当我结束的时候 我说我做完了 所以我返回“done” 所以这非常像map\NAnd 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. -Dialogue: 0,0:24:32.80,0:24:35.12,Default,,0,0,0,,他们之间的差别仅仅是返回值\NIt's mostly different in what it returns. -Dialogue: 0,0:24:35.12,0:24:45.96,Default,,0,0,0,,举一个例子 如果我有一个过程可以在屏幕上输出对象 如果我想打印列表中的对象 我可以调用for-each打印这个列表\NAnd 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. -Dialogue: 0,0:24:46.78,0:24:54.86,Default,,0,0,0,,如果我有一个图形的列表 我想画出他们 我可以用for-each把它们画出来\NOr 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. -Dialogue: 0,0:24:57.92,0:24:59.32,Default,,0,0,0,,大家提问吧\NLet's take questions. -Dialogue: 0,0:25:00.62,0:25:07.54,Default,,0,0,0,,学生:它创建的是一个新对象副本么 如果不明确的告诉它这样做的时候? 是么?\NAUDIENCE: Does it create a new copy with something done to it, unless you explicitly tell it to do that? Is that correct? -Dialogue: 0,0:25:07.54,0:25:09.18,Default,,0,0,0,,对\NPROFESSOR: Right. -Dialogue: 0,0:25:09.18,0:25:10.94,Default,,0,0,0,,就是这样\NYeah, that's right. -Dialogue: 0,0:25:10.94,0:25:15.14,Default,,0,0,0,,for-each不创建新列表 它只是对列表的每一个元素进行处理\NFor-each does not create a List. It just sort of does something. -Dialogue: 0,0:25:15.14,0:25:24.60,Default,,0,0,0,,所以如果你有一堆事情想要做 并且你并不关心这个值 比如打印 绘图 或者在终端中响铃等等\NSo if you have a bunch of things you want to do and you're not worried about values like printing something, or drawing something on the screen, or ringing the bell on the terminal,or for something, -Dialogue: 0,0:25:24.60,0:25:32.42,Default,,0,0,0,,for-each对列表的每一个元素做这件事情 而map其实构建了一个新的集合 这个集合也许是你想要用的\Nyou 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. -Dialogue: 0,0:25:32.42,0:25:34.16,Default,,0,0,0,,这就是他们之间的微妙关系\NIt's just a subtle difference between them. -Dialogue: 0,0:25:34.16,0:25:40.16,Default,,0,0,0,,学生:你可以用for-each写map么?这样就可以用cons或者别的为这个列表做备份\NAUDIENCE: Could you write MAP using for-each, 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,Default,,0,0,0,,老师:某种程度上 我也许可以\NPROFESSOR: Well, sort of. I mean, I probably could. -Dialogue: 0,0:25:44.46,0:25:49.98,Default,,0,0,0,,我不知道如何随手写出它 但是我可以给一些思路\NI can't think of how to do it right offhand, but yeah, I could arrange something. -Dialogue: 0,0:25:50.48,0:26:00.62,Default,,0,0,0,,学生:map和for-each的关键区别在于一个是递归 而另一个不是 你上一节课定义了它\NAUDIENCE: 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. -Dialogue: 0,0:26:01.24,0:26:03.86,Default,,0,0,0,,是的 关于map和for-each和递归\NPROFESSOR: Yeah, about MAP and for-each and recursion. -Dialogue: 0,0:26:03.86,0:26:05.48,Default,,0,0,0,,这个观点很好\NYeah, that's a good point. -Dialogue: 0,0:26:05.48,0:26:13.08,Default,,0,0,0,,我写的map过程恰巧是一个递归过程\NFor the MAP procedure I wrote, that happens to be a recursive process. -Dialogue: 0,0:26:13.08,0:26:21.46,Default,,0,0,0,,原因是当你处理完这个事情 你在等着返回的值 你要用列表的开始元素跟它连接在一起\NAnd 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, -Dialogue: 0,0:26:21.46,0:26:24.84,Default,,0,0,0,,但是for-each不需要等待返回值\Nwhereas for-each doesn't really have any values to wait for. -Dialogue: 0,0:26:24.84,0:26:26.66,Default,,0,0,0,,所以它变成了一个迭代的过程\NSo that turns out to be an iterative process. -Dialogue: 0,0:26:26.66,0:26:27.72,Default,,0,0,0,,这个不是基本原则\NThat's not fundamental. -Dialogue: 0,0:26:27.72,0:26:32.08,Default,,0,0,0,,我已经定义了map所以它可以变成一个迭代过程\NI could have defined MAP so that it's evolved by an iterative process. -Dialogue: 0,0:26:32.08,0:26:34.08,Default,,0,0,0,,是我没有那么做\NI just didn't happen to. -Dialogue: 0,0:26:34.24,0:26:42.90,Default,,0,0,0,,学生:如果你用cons连接列表生成列表的列表 我想这个应该是可行的\NAUDIENCE: If you were to cons 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,Default,,0,0,0,,它会返回这些内部列表的内部元素么?\NIt would give you the internal elements of each of those internal Lists? -Dialogue: 0,0:26:48.70,0:26:50.40,Default,,0,0,0,,老师:问题是如果我[不详]\NPROFESSOR: OK, the question is if I [UNINTELLIGIBLE] -Dialogue: 0,0:26:50.40,0:27:00.60,Default,,0,0,0,,对于for-each和map元素是列表的列表 虽然我们还没有讲过这个 但是那是可行的\Nfor-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. -Dialogue: 0,0:27:01.02,0:27:06.56,Default,,0,0,0,,答案是肯定的 我的意思是这么做是可行的 但跟你想的不同\NThe answer is yes in the sense I mean work and no in the sense that you mean work, -Dialogue: 0,0:27:06.56,0:27:21.46,Default,,0,0,0,,因为如果我给你一个列表你知道列表中的元素不一定是数字 也许是另一个列表 cons或者是别的什么东西\Nbecause 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, -Dialogue: 0,0:27:21.46,0:27:24.54,Default,,0,0,0,,for-each只是对这个列表中的每一个元素做一些事情(不会考虑元素是否还是列表)\Nfor-each just says do something to each item in this List. -Dialogue: 0,0:27:24.54,0:27:26.96,Default,,0,0,0,,for-each连续的向后找cdr\NIt goes down successively looking at the cdrs. -Dialogue: 0,0:27:26.96,0:27:27.20,Default,,0,0,0,,学生:嗯\NAUDIENCE: OK. -Dialogue: 0,0:27:27.20,0:27:31.06,Default,,0,0,0,,老师:它所关心的是 列表的第一个元素是不是会停在这里。#TBD\NPROFESSOR: 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,Default,,0,0,0,,学生:唔\NAUDIENCE: Mhm. -Dialogue: 0,0:27:31.65,0:27:33.94,Default,,0,0,0,,老师:这也许是对的 也许不是\NPROFESSOR: That might or might not be the right thing. -Dialogue: 0,0:27:33.94,0:27:35.57,Default,,0,0,0,,学生:所以不能进入(列表的元素中)\NAUDIENCE: So it wouldn't go down into the-- -Dialogue: 0,0:27:35.57,0:27:36.91,Default,,0,0,0,,老师:绝对不能\NPROFESSOR: Absolutely not. -Dialogue: 0,0:27:36.91,0:27:38.51,Default,,0,0,0,,我可以写一些别的东西\NI could certainly write something else. -Dialogue: 0,0:27:38.51,0:27:47.94,Default,,0,0,0,,这里有一个你正在寻找的通用模式 叫做树递归 当你给它一个列表 它进入树的叶子节点\NThere'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. -Dialogue: 0,0:27:47.94,0:27:51.05,Default,,0,0,0,,你可以写出来这个过程 但是它不是for-each 也不是map\NAnd 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,Default,,0,0,0,,记住for-each和map都很简单\NRemember, these things are really being very simple minded. -Dialogue: 0,0:27:55.77,0:27:57.11,Default,,0,0,0,,好 还有问题么?\NOK, no more questions? -Dialogue: 0,0:27:57.11,0:27:59.11,Default,,0,0,0,,好的 大家休息一下吧\NAll right, let's break. -Dialogue: 0,0:27:59.11,0:28:41.94,Default,,0,0,0,,[MUSIC PLAYING] -Dialogue: 0,0:28:41.94,0:28:48.65,Default,,0,0,0,,老师:我现在要在这节课的剩下时间要做的事情是一个示例\NPROFESSOR: What I'd like to do now is spend the rest of this time talking about one example, -Dialogue: 0,0:28:48.65,0:28:54.65,Default,,0,0,0,,这个示例 可以充分的总结我们现在所学的所有东西\Nand this example, I think, pretty much summarizes everything that we've done up until now: -Dialogue: 0,0:28:54.65,0:29:04.60,Default,,0,0,0,,对 这个是列表结构和抽象议题 还有高阶函数的表示 捕获通用性\Nall right, and that's List structure and issues of abstraction, and representation and capturing commonality with higher order procedures, -Dialogue: 0,0:29:04.60,0:29:13.62,Default,,0,0,0,,还有介绍我们没有谈论太多的事情--这个是这个课程的第三个主题\Nand 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:13.62,0:29:25.80,Default,,0,0,0,,原语言抽象 它的思想来自为复杂的工程设计构建一个合适的强悍的语言\Nmeta-linguistic abstraction, which is the idea that one of the ways of tackling complexity in engineering design is to build a suitable powerful language. -Dialogue: 0,0:29:27.91,0:29:34.74,Default,,0,0,0,,你可以回想 我要告诉大家的在这个课上非常重要的事情\NYou 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,Default,,0,0,0,,当你思考一个语言 你想它依据什么基本元素\Nwhen you think about a language,you think about it in terms of what are the primitives; -Dialogue: 0,0:29:41.17,0:29:47.28,Default,,0,0,0,,意思是(用什么进行)组合----\Nwhat are the means of combination-- -Dialogue: 0,0:29:47.28,0:29:53.22,Default,,0,0,0,,什么基本元素可以让你构建更大事物\Nright, what are the things that allow you to build bigger things; -Dialogue: 0,0:29:53.22,0:29:55.88,Default,,0,0,0,,第二 抽象的意义\Nand then what are the means of abstraction. -Dialogue: 0,0:30:00.97,0:30:11.71,Default,,0,0,0,,如何处理那些大对象?围绕这个对象构建一些黑盒 把这个对象当作参数 然后去做更复杂的事情\NHow 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? -Dialogue: 0,0:30:13.25,0:30:23.01,Default,,0,0,0,,我的朋友Peter Handerson发明了一个特别语言\NNow the particular language I'm going to talk about is an example that was made up by a friend of ours called Peter Henderson. -Dialogue: 0,0:30:27.85,0:30:31.94,Default,,0,0,0,,他在苏格兰的斯特灵大学\NPeter Henderson is at the University of Stirling in Scotland. -Dialogue: 0,0:30:31.94,0:30:41.28,Default,,0,0,0,,这个语言的是像这样画图用的\NAnd what this language is about is making figures that sort of look like this. -Dialogue: 0,0:30:41.28,0:30:46.91,Default,,0,0,0,,这个是一个Escher做的木板画 叫做"方块极限"\NThis is this is a woodcut by Escher called "Square Limit." -Dialogue: 0,0:30:49.14,0:30:58.45,Default,,0,0,0,,它很复杂 里面有图像的递归\NYou, sort of, see it has this complicated, kind of, recursive, sort of,\N是一种图像的递归,\Nrecursive kind of figure, -Dialogue: 0,0:30:58.45,0:31:05.05,Default,,0,0,0,,中间的这个鱼的模式不断以更小的图案出现在原来的图案旁边\Nwhere there's this fish pattern in the middle and things sort of bleed out smaller and smaller in self similar ways. -Dialogue: 0,0:31:08.14,0:31:18.28,Default,,0,0,0,,总之Peter Hendersion的语言是用来表述这些图形 并且设计新的图形 像这样 并将它画在显示器上\NAnyway, 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. -Dialogue: 0,0:31:19.88,0:31:32.02,Default,,0,0,0,,我们从这个示例中可以看到另外一个主题 这个是我跟Gerry已经多次提到的:\NThere'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: -Dialogue: 0,0:31:32.02,0:31:36.65,Default,,0,0,0,,通常 过程跟数据之间没有真正的区别\Nthat there's no real difference, in some sense, between procedures and data. -Dialogue: 0,0:31:36.65,0:31:47.60,Default,,0,0,0,,我希望今天早晨结束后 我希望大家彻底“混消”(不要区别对待)过程跟数据的差别\NAnd anyway I hope by the end of this morning, if you're not already, you will be completely confused about what the difference between procedures and data are, -Dialogue: 0,0:31:47.60,0:31:50.05,Default,,0,0,0,,如果你还没有"混消"(那么就开始吧)\Nif you're not confused about that already. -Dialogue: 0,0:31:50.05,0:31:55.28,Default,,0,0,0,,好的 让我们开始表述一下Peter的语言 \NWell in any case, let's start describing Peter's language. -Dialogue: 0,0:31:55.28,0:31:57.97,Default,,0,0,0,,我将要开始告诉你基本元素是什么\NI should start by telling you what the primitives are. -Dialogue: 0,0:31:57.97,0:32:01.37,Default,,0,0,0,,这个语言非常简单 因为它的基本元素就只有一个\NThis language is very simple because there's only one primitive. -Dialogue: 0,0:32:03.05,0:32:06.68,Default,,0,0,0,,这个基本元素不是大家想象的那样\NA primitive is not quite what you think it is. -Dialogue: 0,0:32:06.68,0:32:12.11,Default,,0,0,0,,只有一个基本元素叫做"图像" 但是这个图像不是我们平时认为的图像\NThere's only one primitive called a picture, and a picture is not quite what you think it is. -Dialogue: 0,0:32:12.11,0:32:14.17,Default,,0,0,0,,举一个例子\NHere's an example. -Dialogue: 0,0:32:14.17,0:32:15.48,Default,,0,0,0,,这里有一个George的图像\NThis is a picture of George. -Dialogue: 0,0:32:18.77,0:32:31.85,Default,,0,0,0,,基本想法是:在这个语言中的图像是绘制通过缩放填充到指定矩行区域的一个图形产生的\NThe 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. -Dialogue: 0,0:32:32.68,0:32:34.42,Default,,0,0,0,,所以大家看「不明」\NSo here you see in [? Saint ?] [? Lawrence's ?] -Dialogue: 0,0:32:34.42,0:32:42.62,Default,,0,0,0,,这个矩形的轮廓 这个不是图像的一部分 但是图像--\Noutline of a rectangle, that's not really part of the picture, but the picture-- -Dialogue: 0,0:32:42.62,0:32:47.17,Default,,0,0,0,,一旦指定一个矩形区域 图像可以绘制这个图形来填充这个矩形区域\Nyou'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.77,Default,,0,0,0,,比如 这个是George 在这里 这个也是George\NSo for example, there's George, and here, this is also George. -Dialogue: 0,0:32:52.77,0:32:56.94,Default,,0,0,0,,他们是同一个图像 只是经过不同的缩放填充这个矩形而已\NIt's the same picture, right, just scaled to fit a different rectangle. -Dialogue: 0,0:32:56.94,0:32:59.48,Default,,0,0,0,,这是一个George的“胖”版本\NHere's George as a fat kid. -Dialogue: 0,0:32:59.48,0:33:03.68,Default,,0,0,0,,这个也是George\NThat's the same George. -Dialogue: 0,0:33:03.68,0:33:05.14,Default,,0,0,0,,这是同一个图形\NIt's all the same figure. -Dialogue: 0,0:33:05.14,0:33:08.57,Default,,0,0,0,,在这个语言中 这三个东西是同一个图像\NAll of these three things are the same picture in this language. -Dialogue: 0,0:33:08.57,0:33:13.25,Default,,0,0,0,,仅仅是给了不同的矩形让他们来填充\NI'm just giving it different rectangles to scale itself in. -Dialogue: 0,0:33:16.08,0:33:20.65,Default,,0,0,0,,这就是这个语言的基本原则\NOK, those are the primitives. \N就这一个原则。\NThat is the primitive. -Dialogue: 0,0:33:20.65,0:33:25.60,Default,,0,0,0,,现在我们开始讨论一下元素组合和操作\NNow let's start talking about the means of combination and the operations. -Dialogue: 0,0:33:25.60,0:33:30.17,Default,,0,0,0,,比如 这里有一个操作叫做旋转\NThere is, for example, an operation called Rotate. -Dialogue: 0,0:33:30.17,0:33:40.30,Default,,0,0,0,,旋转要做的是事情是:给一个图像 比如一个图像 这个图像在我给定的矩行中绘制"A"\NAnd what Rotate does is, if I have a picture, say a picture that draws an "A" in some rectangle that I give it, -Dialogue: 0,0:33:41.57,0:33:50.65,Default,,0,0,0,,旋转操作就是--旋转90度 如果我给一个矩形区域 它绘制同样的图案\Nthe Rotate of that--say the Rotate by 90 degrees would, if I give it a rectangle, draw the same image, -Dialogue: 0,0:33:50.65,0:33:54.14,Default,,0,0,0,,但是 对这个图形进行了旋转\Nbut again, scaled to fit that rectangle. -Dialogue: 0,0:33:56.11,0:33:58.34,Default,,0,0,0,,这个就是旋转90度\NSo that's Rotate by 90 degrees. -Dialogue: 0,0:33:58.34,0:34:04.24,Default,,0,0,0,,这里还有一个操作叫做翻转 水平或者竖直方向进行翻转\NThere's another operation called Flip that can flip something, either horizontally or vertically. -Dialogue: 0,0:34:04.24,0:34:10.40,Default,,0,0,0,,好 这些就是操作 大家也可以把他们理解为对一个元素进行组合\NAll right, so those are, sort of, operations, or you can think of those as means of combination of one element. -Dialogue: 0,0:34:10.40,0:34:12.82,Default,,0,0,0,,我可以把他们混合起来\NI can put things together. -Dialogue: 0,0:34:12.82,0:34:25.14,Default,,0,0,0,,这里有一个操作叫做beside 它做的事情是:给定两个图像 比如 A和B ---\NThere's a means of combination called Beside, 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,Default,,0,0,0,,然后它将在一个特殊的矩形中绘制一个图像\Nand 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,Default,,0,0,0,,beside会--\Nand what Beside will do-- -Dialogue: 0,0:34:37.85,0:34:44.08,Default,,0,0,0,,让B靠在A的旁边 还有一个数字S #TBD\NI 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,Default,,0,0,0,,s是一个在0到1之间的数\NAnd s will be a number between zero and one. -Dialogue: 0,0:34:50.51,0:34:52.57,Default,,0,0,0,,beside会像这样画一个图像出来\NAnd Beside will draw a picture that looks like this. -Dialogue: 0,0:34:52.57,0:34:56.71,Default,,0,0,0,,你给定一个矩形区域和图形的缩放比例s\NIt will take the rectangle you give it and scale its base by s. -Dialogue: 0,0:34:56.71,0:34:58.71,Default,,0,0,0,,这里s是0.5\NSay s is 0.5. -Dialogue: 0,0:34:59.97,0:35:12.65,Default,,0,0,0,,在这里它会画--它会在这里画第一个图案 在这里画第二个图案\NAnd 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:13.82,0:35:23.95,Default,,0,0,0,,如果我给一个不同的s 如果我给s不同的值 如果我说 应用beside(使用S)为0.25\NOr 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.34,Default,,0,0,0,,它将做同样的事情 只是A更瘦了\Nit would do the same thing,except the A would be much skinnier. -Dialogue: 0,0:35:34.05,0:35:36.28,Default,,0,0,0,,(beside)就是这样画图的\NSo it would draw something like that. -Dialogue: 0,0:35:37.82,0:35:46.05,Default,,0,0,0,,这就是beside的组合 很简单 也有一个操作叫做above 也是做同样的事情 就是将水平方向的操作用竖直方向的操作替换\NSo 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. -Dialogue: 0,0:35:47.31,0:35:49.57,Default,,0,0,0,,我们看一下它\NWell let's look at that. -Dialogue: 0,0:35:50.74,0:36:11.74,Default,,0,0,0,,对 这个就似乎George和他的"兄弟" 它的构造是通过在George应用一次beside和above--\NAll right, there's George and his kid brother, which is, right, constructed by taking George and putting him Beside the Above-- -Dialogue: 0,0:36:11.74,0:36:16.14,Default,,0,0,0,,系统中有个东西叫做空图案 很明显--\Ntaking the empty picture, and there's a thing called the empty picture, which does the obvious thing-- -Dialogue: 0,0:36:16.14,0:36:19.14,Default,,0,0,0,,空图像放在了George副本的上面\Nputting the empty picture above a copy of George, -Dialogue: 0,0:36:19.14,0:36:21.14,Default,,0,0,0,,然后这个合成的图像放在了George的旁边\Nand then putting that whole thing Beside George. -Dialogue: 0,0:36:28.77,0:36:54.08,Default,,0,0,0,,给beside然后flipping图像George的过程起一个名字叫做P 它水平扩展 然后先旋转整个图像180度 然后将基本的矩形区域分成两半 将原图和现在这个图拼接在一起 我叫它P\NHere'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. -Dialogue: 0,0:36:55.88,0:37:05.05,Default,,0,0,0,,我把P作用在翻转上面 给它起一个名字叫做Q #TBD这里翻译有问题,估计\NAnd 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:21.05,Default,,0,0,0,,我们构建一个复杂情况需要多少时间? 15秒,你就可以从George得到Q 这个是为什么呢?\NNotice 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? -Dialogue: 0,0:37:22.05,0:37:24.55,Default,,0,0,0,,为什么我们可以如此迅速的做呢?\NHow are how we able to do that so fast? -Dialogue: 0,0:37:25.85,0:37:28.02,Default,,0,0,0,,答案是闭包属性\NThe answer is the closure property. -Dialogue: 0,0:37:28.02,0:37:38.25,Default,,0,0,0,,事实是 一个图形 我可以用它来做beside的参数 生成一个图像 然后我可以用这个图像继续进行rotage flip或者above等操作\NSee, 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. -Dialogue: 0,0:37:39.17,0:37:45.22,Default,,0,0,0,,当我对那个图像进行P操作 得到的还是一个图像\NRight, and when I take that element P, 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.60,Default,,0,0,0,,也就是说 对于图像而言 这些组合是封闭的\NRight, the world of pictures is closed under those means of combination. -Dialogue: 0,0:37:50.60,0:37:55.60,Default,,0,0,0,,所以只要给我一个图像 我可以立刻把它作为一个可以在其它地方使用的元素\NSo whenever I have something, I can turn right around and use that as an element in something else. -Dialogue: 0,0:37:55.60,0:38:03.28,Default,,0,0,0,,也许(这个案例)比列表和线段更好 给大家展示了如何快速构建复杂的系统 根本原因是这些操作是封闭的\NSo maybe better than List and segments, that just gives you an image for how fast you can build up complexity, because operations are closed. -Dialogue: 0,0:38:07.22,0:38:15.28,Default,,0,0,0,,在构建更多东西之前 我们谈谈这个语言要如何实现\NOK, well before we go on with building more things, let's talk about how this language is actually implemented. -Dialogue: 0,0:38:16.91,0:38:28.28,Default,,0,0,0,,在这个桌子下面的基本元素叫做矩形区域 矩形区域是: #TBD 需要修改\NThe basic element that sits under the table here is a thing called a rectangle, and what a rectangle is going to be, -Dialogue: 0,0:38:28.28,0:38:40.18,Default,,0,0,0,,它有指定的原点 用来说明这个矩形区域从哪里开始的\Nit's a thing that specified by an origin that's going to be some vector that says where the rectangle starts. -Dialogue: 0,0:38:40.18,0:38:59.58,Default,,0,0,0,,还有其他向量 我叫它矩形区域的水平向量 另一个是矩形区域的竖直向量\NAnd then there's going to be some other vector that I'm going to call the horizontal part of the rectangle, and another vector called the vertical part of the rectangle. -Dialogue: 0,0:39:00.31,0:39:09.97,Default,,0,0,0,,它们三个是三个元素:底坐标在哪里 这里如何获得下一个坐标 这里如何获得下一个坐标\NAnd 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. -Dialogue: 0,0:39:09.97,0:39:12.37,Default,,0,0,0,,这三个向量确定了一个矩形\NThe three vectors specify a rectangle. -Dialogue: 0,0:39:15.77,0:39:39.65,Default,,0,0,0,,现在为了构建了矩形 我们假定我们已经有了一个构造器 叫做make rectangle 或者make-rect 它的水平,竖直,原点的选择器是horiz, vert, origin\NNow 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. -Dialogue: 0,0:39:39.65,0:39:42.54,Default,,0,0,0,,大家知道有很多方法可以实现它\NAnd well, you know a lot of ways you can do this now. -Dialogue: 0,0:39:42.54,0:39:47.62,Default,,0,0,0,,大家可以用pair或者列表或者别的什么东西来做\NYou 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,Default,,0,0,0,,但是,实现这个是George该去想的问题\NBut in any case, the implementation of these things, that's George's problem. -Dialogue: 0,0:39:51.40,0:39:53.17,Default,,0,0,0,,这就是一个数据抽象问题\NIt's just a data representation problem. -Dialogue: 0,0:39:53.17,0:39:55.47,Default,,0,0,0,,现在我们假设已经有了这三个矩形\NSo let's assume we have these rectangles to work with. -Dialogue: 0,0:40:02.05,0:40:05.08,Default,,0,0,0,,记住要做什么\NOK. Now the idea of this, remember what's got to happen. -Dialogue: 0,0:40:05.08,0:40:16.60,Default,,0,0,0,,我们需要操心的是:给定一个图案 对它进行缩放来填充给定的矩形 这个是我们需要做的\NSomehow 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, -Dialogue: 0,0:40:16.60,0:40:18.60,Default,,0,0,0,,that these pictures can do. -Dialogue: 0,0:40:22.22,0:40:23.65,Default,,0,0,0,,我们要怎么做呢?\NHow do we think about that? -Dialogue: 0,0:40:23.65,0:40:38.85,Default,,0,0,0,,其中的一种方法是任何时候给定一个矩行\NWell, one way to think about that is that any time I give you a rectangle, -Dialogue: 0,0:40:39.25,0:40:45.77,Default,,0,0,0,,定义 在某种意义上 把一个正方形转化成矩形.\Nthat defines,in some sense, a transformation from the standard square into that rectangle. -Dialogue: 0,0:40:45.77,0:40:46.54,Default,,0,0,0,,我们来看一下我所说的\NLet me say what I mean. -Dialogue: 0,0:40:46.54,0:40:59.04,Default,,0,0,0,,一个标准的正方形 它的坐标是(0,0)(1,0)(1,1)\NBy 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. -Dialogue: 0,0:41:01.40,0:41:10.34,Default,,0,0,0,,有一些显然的缩放变换 可以把这个变成那个 把这个变成那个\NAnd there's some sort of the obvious scaling transformation, which maps this to that and this to that, -Dialogue: 0,0:41:10.34,0:41:12.08,Default,,0,0,0,,还有一些对每一个向量进统一拉伸的方法\Nand sort of, stretches everything uniformly. -Dialogue: 0,0:41:12.17,0:41:32.68,Default,,0,0,0,,我们像这样做一个线段 并且做它的映射像这样 所以点(x,y)变成了另外一个点\NSo we take a line segment like this and end up mapping it to a line segment like that, so some point (x,y) goes to some other point up there. -Dialogue: 0,0:41:32.68,0:41:39.37,Default,,0,0,0,,虽然这个不重要 就是一点点的代数几何 大家可以容易的把公式写出来\NAnd although it's not important,with a little vector algebra, you could write that formula. -Dialogue: 0,0:41:39.37,0:41:50.67,Default,,0,0,0,,点(x,y)会变到 用矩阵的原点和它做向量加法 --\NThe thing that (x,y) goes to, the point that (x,y) goes to is gotten by taking the origin of the rectangle and then adding that as a vector to-- -Dialogue: 0,0:41:50.67,0:42:01.97,Default,,0,0,0,,x坐标 这个值在0到1之间 乘以矩阵的水平向量\Nwell, take x, the x coordinate, which is something between zero and one, multiply that by the horizontal vector of the rectangle; -Dialogue: 0,0:42:07.22,0:42:16.28,Default,,0,0,0,,y坐标 这个值也在0到1之间 乘以矩阵的竖直向量\Nand take the y coordinate, which is also something between zero and one and multiply that by the vertical vector of the rectangle. -Dialogue: 0,0:42:16.74,0:42:19.31,Default,,0,0,0,,这个是简单地线性代数\NThat's just a little linear algebra. -Dialogue: 0,0:42:19.31,0:42:28.51,Default,,0,0,0,,这个公式明显正确的把正方形中的元素转换成了矩阵的内部元素\NAnyway, that's the formula, which is the right obvious transformation that takes things into the unit square, into the interior of that rectangle. -Dialogue: 0,0:42:31.34,0:42:34.02,Default,,0,0,0,,好,我们把它看作是一个过程\NOK well, let's actually look at that as a procedure. -Dialogue: 0,0:42:35.05,0:42:42.85,Default,,0,0,0,,所以我们要做的事情是定义一个矩形的转化过程\NSo what we want is the thing which tells us that particular transformation that a rectangle defines. -Dialogue: 0,0:42:43.80,0:42:45.22,Default,,0,0,0,,就是这个过程\NSo here's the procedure. -Dialogue: 0,0:42:45.22,0:42:47.22,Default,,0,0,0,,我叫它coordinate-map\NI'll call it coordinate-map. -Dialogue: 0,0:42:47.77,0:42:57.85,Default,,0,0,0,,coordinate-map需要一个矩形作为参数,它返回需要一个点坐标作为参数的过程\NCoordinate-map is the thing that takes as its argument a rectangle and returns for you a procedure on points. -Dialogue: 0,0:43:00.45,0:43:06.82,Default,,0,0,0,,所以对每一个矩形,你都有个转换函数将一个点(x,y)转换到这个矩形里面\NRight, 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,Default,,0,0,0,,如何做呢?\NAnd how do you get it? -Dialogue: 0,0:43:08.02,0:43:10.92,Default,,0,0,0,,我只是--在黑板上用列表实现 #TBD 这个是list 还是lisp 不确定\NWell I just-- writing in List what I wrote there on the blackboard-- -Dialogue: 0,0:43:10.92,0:43:20.20,Default,,0,0,0,,矩形的原点--\NI add to the origin of the rectangle the result of adding-- -Dialogue: 0,0:43:20.22,0:43:25.02,Default,,0,0,0,,我用矩形的水平向量\NI take the horizontal part of the rectangle; -Dialogue: 0,0:43:25.02,0:43:27.68,Default,,0,0,0,,来对点point的x坐标缩放\NI scale that by the x coordinate of the point. -Dialogue: 0,0:43:29.65,0:43:32.62,Default,,0,0,0,,我用矩形的竖直向量,\NI take the vertical vector of the rectangle. -Dialogue: 0,0:43:33.51,0:43:37.14,Default,,0,0,0,,来对point的y坐标进行缩放\NI scale that by the y coordinate of the point, -Dialogue: 0,0:43:37.14,0:43:39.14,Default,,0,0,0,,然后把他们三个加到一起\Nand then add all those three things up. -Dialogue: 0,0:43:39.34,0:43:41.34,Default,,0,0,0,,这就是这个过程\NThat's the procedure. -Dialogue: 0,0:43:41.34,0:43:44.54,Default,,0,0,0,,这就是我将要应用在point上的过程\NThat is the procedure that I'm going to apply to a point. -Dialogue: 0,0:43:46.54,0:43:52.17,Default,,0,0,0,,每一个矩形都可以产生这样一个过程\NAnd this whole thing is generated for each rectangle. -Dialogue: 0,0:43:52.17,0:43:57.25,Default,,0,0,0,,所以任何一个矩形定义一个coordinate-map,返回一个作用在point上的过程\NSo any rectangle defines a coordinate MAP, which is a procedure on points. -Dialogue: 0,0:44:06.51,0:44:28.17,Default,,0,0,0,,比如,原始的George,在这个正方形单元中有一些线段,只要我指定一个矩行,就可以把这些线段映射过来.\NAll 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. -Dialogue: 0,0:44:28.17,0:44:30.17,Default,,0,0,0,,我实际是怎么做的呢?\NHow actually do I do that? -Dialogue: 0,0:44:30.17,0:44:44.45,Default,,0,0,0,,我把原来在George中的每一个线段的原点和结束点应用到coordinate-map上。#TBD\NWell 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. -Dialogue: 0,0:44:44.45,0:44:51.25,Default,,0,0,0,,比如,这个矮矩形,图像George用coordinate-map变换后变成一个胖子\NSo for example, this lower rectangle, this George as a fat kid rectangle, has its coordinate MAP. -Dialogue: 0,0:44:51.25,0:45:05.34,Default,,0,0,0,,如果我要绘制这个图像,我要做的就是对这里的每一个线段,用coordinate-map映射线段的段点\NAnd 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. -Dialogue: 0,0:45:05.34,0:45:09.22,Default,,0,0,0,,它将给我这个点和那个点,并且在这两个点中画一个线段\NThat will give me this point and that point and draw the segment between them. -Dialogue: 0,0:45:09.71,0:45:11.52,Default,,0,0,0,,对,基本想法就是这样\NRight, that's the idea. -Dialogue: 0,0:45:12.66,0:45:18.14,Default,,0,0,0,,像这样如果我给一个不同的矩形,那么(会产生)不同的coordinate-map,因此我得到这些线段的不同图像\NRight, 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. -Dialogue: 0,0:45:19.28,0:45:22.14,Default,,0,0,0,,我们如何获得最开始的图像呢?\NWell how do we actually get a picture to start with? -Dialogue: 0,0:45:22.14,0:45:26.52,Default,,0,0,0,,我们可以用线段列表获得最初的图像.\NI can build a picture to start with out of a List of line segments initially. -Dialogue: 0,0:45:27.50,0:45:37.52,Default,,0,0,0,,这是一个我构建最基本图像的过程,意思是,我没有用beside,rotate等构建图像\NHere'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. -Dialogue: 0,0:45:37.52,0:45:44.04,Default,,0,0,0,,我用线段的列表,他们按照我说的来工作\NIt starts with a List of line segments, and now it does what I said. -Dialogue: 0,0:45:44.04,0:45:45.58,Default,,0,0,0,,图像会是什么样子呢?\NWhat's a picture have to be? -Dialogue: 0,0:45:45.58,0:45:49.44,Default,,0,0,0,,首先,它是一个根据矩形定义的过程\NFirst of all it's a procedure that's defined on rectangles. -Dialogue: 0,0:45:51.70,0:45:53.00,Default,,0,0,0,,这个过程做什么呢?\NWhat does it do? -Dialogue: 0,0:45:53.00,0:46:07.30,Default,,0,0,0,,线段构成的列表中的每一个元素s,它自己画一条线段.\NIt 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. -Dialogue: 0,0:46:07.30,0:46:08.82,Default,,0,0,0,,它画什么样的线段呢?\NWhat line does it draw? -Dialogue: 0,0:46:10.46,0:46:18.32,Default,,0,0,0,,线段的起点,通过在特定矩形的coordinate-map变换\NIt gets the start point of that segment, transforms that by the coordinate MAP of the rectangle. -Dialogue: 0,0:46:19.54,0:46:21.76,Default,,0,0,0,,这个就是第一个想要的新的点\NThat's the first new point it wants to do. -Dialogue: 0,0:46:21.76,0:46:27.92,Default,,0,0,0,,线段的终点,通过这个矩形的coordinate-map变换得到新点,在新起点和新终点之间画一个线段\NThen it takes the endpoint of the segment, transforms that by the coordinate MAP of the rectangle, and then draws a line between. -Dialogue: 0,0:46:27.92,0:46:33.22,Default,,0,0,0,,我们假设画线是一个基本的操作,已经在系统中实现了.\NLet's assume drawline is some primitive that's built into the system that actually draws a line on the display. -Dialogue: 0,0:46:33.96,0:46:44.22,Default,,0,0,0,,通过矩形的坐标映射变换了线段两段点,在新段点间画一个线段.线段列表的每一个线段s都会进行这样的操作\NAll 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. -Dialogue: 0,0:46:45.96,0:46:51.40,Default,,0,0,0,,现在要记住,一个图像就是一个用矩形作为参数的过程.\NAnd now remember again, a picture is a procedure that takes a rectangle as argument. -Dialogue: 0,0:46:51.40,0:46:56.36,Default,,0,0,0,,所以当你有一个矩形的时候,它所做的事情就是:画这些线段.\NSo when you hand it a rectangle, this is what it does: draws those lines. -Dialogue: 0,0:46:56.36,0:47:01.22,Default,,0,0,0,,好,我应该如何使用它呢?\NAll right, so there's-- how would I actually use this thing? -Dialogue: 0,0:47:01.22,0:47:04.08,Default,,0,0,0,,我来说的具体一点\NLet's make it a little bit more concrete. -Dialogue: 0,0:47:05.60,0:47:29.18,Default,,0,0,0,,举例来说,定义R是make-rectangle的过程,我需要用make-vector来生成一些向量\NRight, 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. -Dialogue: 0,0:47:29.84,0:47:46.18,Default,,0,0,0,,然后,定义G为make-picture的过程\NAnd 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,Default,,0,0,0,,这里声明一个线段列表,叫做make-segment\NAnd 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,Default,,0,0,0,,make-segment由向量构成,向量由点构成\NMake-segment might be made out of vectors, and vectors might be made out of points. -Dialogue: 0,0:47:59.26,0:48:11.72,Default,,0,0,0,,如果我想看G里面矩形的图像,它是一个用这个矩形作为参数的过程\NAnd 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. -Dialogue: 0,0:48:11.92,0:48:23.62,Default,,0,0,0,,所以,如果用R作为参数调用G,图像G将会在矩形R来绘制出来.\NSo 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. -Dialogue: 0,0:48:23.62,0:48:25.62,Default,,0,0,0,,这就是大家如何使用它\NRight, so that's how you'd use that. -Dialogue: 0,0:48:25.62,0:49:07.28,Default,,0,0,0,,[MUSIC PLAYING] -Dialogue: 0,0:49:07.72,0:49:12.48,Default,,0,0,0,,老师:为什么我说这个例子很好呢?\NPROFESSOR: Well why is it that I say this example is nice? -Dialogue: 0,0:49:12.48,0:49:13.74,Default,,0,0,0,,大家也许不觉得它很好.\NYou probably don't think it's nice. -Dialogue: 0,0:49:13.74,0:49:15.42,Default,,0,0,0,,大家可能觉得它很奇怪\NYou probably think it's more weird than nice. -Dialogue: 0,0:49:15.42,0:49:20.92,Default,,0,0,0,,对,这些图像用过程来表示,用矩形来做一些复杂的事情(变换)\NRight, representing these pictures as procedures, which do complicated things with rectangles. -Dialogue: 0,0:49:20.92,0:49:22.72,Default,,0,0,0,,那么,它好在哪里呢?\NSo why is it nice? -Dialogue: 0,0:49:25.02,0:49:35.22,Default,,0,0,0,,它很好的原因是,一旦你是实现了其中的基本元素---把过程的实现跟组合分离出来.\NThe 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. -Dialogue: 0,0:49:35.98,0:49:37.48,Default,,0,0,0,,我来展示一下我的想法.\NLet me show you what I mean. -Dialogue: 0,0:49:37.48,0:49:39.48,Default,,0,0,0,,假如我想实现beside\NSuppose we want to implement Beside. -Dialogue: 0,0:49:41.56,0:49:47.36,Default,,0,0,0,,所以我要做---假设我有一个图像,把它叫做P1\NSo 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,Default,,0,0,0,,P1是--现在要明白真正的图像是什么(一个过程)\NP1 is going to be-- and now remember what a picture really is. -Dialogue: 0,0:49:50.62,0:50:01.92,Default,,0,0,0,,如果你给P1一个矩形,它会在你给定的矩形中绘制图像.\NIt'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. -Dialogue: 0,0:50:03.14,0:50:09.64,Default,,0,0,0,,假设P2,是另外的图像,你用一个矩形处理它,\NAnd suppose P2 two is some other picture, and you hand that a rectangle. -Dialogue: 0,0:50:09.64,0:50:12.54,Default,,0,0,0,,无论你给它什么矩形,它都会绘制一些图案.\NAnd whatever rectangle you hand it, it draws some picture. -Dialogue: 0,0:50:14.66,0:50:28.38,Default,,0,0,0,,现在,我想实现beside,用P1,P2,还有一个缩放因子a, 那会发生什么呢?\NAnd now if I'd like to implement Beside of P1 and P2 with a scale factor A, well what does that have to be? -Dialogue: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,,它得绘制出一个图像。你给定一个矩形,它就在这个矩形中绘制一些图像\NThat'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. -Dialogue: 0,0:50:34.62,0:50:40.30,Default,,0,0,0,,所以,如果把Beside放到矩形里,---我们在这个矩行中处理它.\NSo if hand Beside this rectangle-- let's hand it a rectangle. -Dialogue: 0,0:50:41.50,0:50:42.74,Default,,0,0,0,,要做什么呢?\NWell what's it going to do? -Dialogue: 0,0:50:42.76,0:50:55.38,Default,,0,0,0,,它将把这个矩形切分成两部分,一部分比例是a,另一部分比例是(1-a). 那是说,现在我们有两个矩形\NIt'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. -Dialogue: 0,0:51:02.02,0:51:09.84,Default,,0,0,0,,现在(beside)进入P1,对P1说,在这个矩形中绘制你自己,然后进入P2,对P2说,\NAnd now it goes off to P1 and says P1, well draw yourself in this rectangle, and goes off to P2, and says, P2, -Dialogue: 0,0:51:09.84,0:51:11.84,Default,,0,0,0,,在这个矩形中绘制你自己\Nfine, draw yourself in this rectangle. -Dialogue: 0,0:51:13.28,0:51:16.88,Default,,0,0,0,,它所做的所有计算就是计算出有多少个矩形.\NThe only computation it has to do is figure out what these rectangles are. -Dialogue: 0,0:51:17.36,0:51:26.38,Default,,0,0,0,,要记住,一个矩形是原点,水平向量,竖直向量组成的,它要做的就是把他们找出来\NRemember 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. -Dialogue: 0,0:51:27.30,0:51:38.00,Default,,0,0,0,,所以对第一个矩形来说,原点变成了矩形的原点,竖直向量和原始的矩形保持不变\NSo 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. -Dialogue: 0,0:51:38.70,0:51:46.60,Default,,0,0,0,,水平向量是原始矩形的竖直向量缩放a得到的\NThe horizontal vector is the horizontal vector of the original rectangle scaled by A. -Dialogue: 0,0:51:47.38,0:51:49.26,Default,,0,0,0,,这就是第一个矩形\NAnd that's the first rectangle. -Dialogue: 0,0:51:49.46,0:52:00.06,Default,,0,0,0,,第二个矩形的原点是原来的矩形的原点加上矩形的水平向量缩放a,\NThe second rectangle, the origin is the original origin plus that horizontal vector scaled by A. -Dialogue: 0,0:52:00.90,0:52:11.66,Default,,0,0,0,,第二个矩形的水平向量,是矩形的水平向量减去第一个的水平向量,是(1-a)*h\NThe 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, -Dialogue: 0,0:52:11.66,0:52:14.36,Default,,0,0,0,,它的竖直向量还是v\Nand the vertical vector is still v. -Dialogue: 0,0:52:15.22,0:52:26.56,Default,,0,0,0,,基本上,它构造了两个矩形,更重要的是,构造的这两个矩形p1,在这里让它绘制它自己,矩形p2,让它在这里绘制它自己。这就是beside所做的事情\NBut 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. -Dialogue: 0,0:52:27.68,0:52:29.86,Default,,0,0,0,,我们看一下代码\NAll right, let's look at that piece of code. -Dialogue: 0,0:52:34.20,0:52:53.76,Default,,0,0,0,,用一个缩放比例来对一个图像和另一个图像应用biside, 首先,这个图像也是一个过程,接受一个矩形作为它的参数\NBeside 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. -Dialogue: 0,0:52:55.38,0:52:56.76,Default,,0,0,0,,它做什么呢?\NWhat's it going to do? -Dialogue: 0,0:52:56.76,0:53:02.32,Default,,0,0,0,,p1在一些矩形中绘制它自己,p2在另外的一些矩形中绘制它自己\NIt says, p1 draw yourself in some rectangle and p2 draw yourself in some other rectangle. -Dialogue: 0,0:53:02.90,0:53:04.46,Default,,0,0,0,,现在这些矩形是什么呢?\NAnd now what are those rectangles? -Dialogue: 0,0:53:04.46,0:53:05.48,Default,,0,0,0,,这里就是计算\NWell here's the computation. -Dialogue: 0,0:53:05.48,0:53:10.40,Default,,0,0,0,,它创建了一个矩形,这个是我刚才在黑板上写的几何公式--- 原点\NIt makes a rectangle, and this is the algebra I just did on the board: the origin, something; -Dialogue: 0,0:53:10.40,0:53:11.84,Default,,0,0,0,,水平向量;\Nthe horizontal vector, something; -Dialogue: 0,0:53:11.84,0:53:13.44,Default,,0,0,0,,竖直向量\Nand the vertical vector, something. -Dialogue: 0,0:53:13.80,0:53:19.78,Default,,0,0,0,,对于p2,矩形需要不同的原点,水平向量和竖直向量\NAnd for p2, the rectangle it wants has some other origin and horizontal vector and vertical vector. -Dialogue: 0,0:53:19.78,0:53:27.18,Default,,0,0,0,,但是最重要的是,p1,在一个矩形中做你指定的事情,而p2在另一个矩形中做你指定的事情\NBut 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. -Dialogue: 0,0:53:27.74,0:53:29.42,Default,,0,0,0,,这个就是beside做的\NThat's all the Beside has to do. -Dialogue: 0,0:53:30.62,0:53:35.62,Default,,0,0,0,,好,rotate也很类似\NOK, similarly Rotate-- -Dialogue: 0,0:53:36.96,0:53:52.32,Default,,0,0,0,,我有这个图像a,我想看图像a旋转90度,这意味着,给定这个矩形\Nsee 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, -Dialogue: 0,0:53:53.76,0:54:09.32,Default,,0,0,0,,这个矩形的原始原点,水平向量,竖直向量,现在假设已经有了这样的矩形,这个矩形的原点,水平向量,在这,竖直向量在这\Nwhich 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, -Dialogue: 0,0:54:09.60,0:54:12.46,Default,,0,0,0,,然后在矩形里各自绘制自己.\Nand now draw yourself with respect to that rectangle. -Dialogue: 0,0:54:13.26,0:54:15.04,Default,,0,0,0,,我来展示这个过程\NLet me show you that as a procedure. -Dialogue: 0,0:54:16.76,0:54:26.34,Default,,0,0,0,,我们对这个图像旋转90度,因为过程也是一个图像,它可以在特定的矩形中绘制自己\NAll right, so we'll Rotate 90 of the picture, because again, a procedure for rectangle, which says, OK picture, draw yourself in some rectangle; -Dialogue: 0,0:54:27.10,0:54:30.66,Default,,0,0,0,,并且这个几何公式就是这个矩形的变换规则\Nand then this algebra is the transformation on the rectangle. -Dialogue: 0,0:54:30.66,0:54:34.16,Default,,0,0,0,,It's the one which makes it look like the rectangle is sideways, -Dialogue: 0,0:54:34.16,0:54:40.06,Default,,0,0,0,,原点在别的地方;竖直向量在别的地方;水平向量在别的地方;竖直向量在别的地方\Nthe origin is someplace else and the vertical vector is someplace else, and the horizontal vector is someplace else, and vertical vector is someplace else. -Dialogue: 0,0:54:46.76,0:55:01.26,Default,,0,0,0,,再次注意,这里的关键是使用过程来做图片的表示,这个过程本身有闭包的特性,\NOK, 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, -Dialogue: 0,0:55:01.74,0:55:05.22,Default,,0,0,0,,beside对于p1,\Nbecause what happens is, Beside just has this thing p1. -Dialogue: 0,0:55:05.22,0:55:12.90,Default,,0,0,0,,beside不关心那个是不是主要的图像,或者是线段,或者这个是不是由above, beside,rotate生成的,//\NBeside 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. -Dialogue: 0,0:55:12.90,0:55:20.00,Default,,0,0,0,,beside所知道的就是,如果你给p1一个矩形,它会在这个矩形中绘制(p1)\NAll Beside has to know about, say, p1 is that if you hand p1 a rectangle, it will cause something to be drawn. -Dialogue: 0,0:55:20.82,0:55:26.10,Default,,0,0,0,,在这个层面上,beside不关心p1是如何绘制自己的\NAnd above that level, Beside just doesn't-- it's none of its business how p1 accomplishes that drawing. -Dialogue: 0,0:55:27.42,0:55:32.54,Default,,0,0,0,,对,这就是使用过程表示图像保证了这个(系统)闭包的\NAll right, so you're using the procedural representation to ensure this closure. -Dialogue: 0,0:55:35.64,0:55:43.84,Default,,0,0,0,,所以用过程来实现图片,使得组合的意义非常简单,并且优美\NSo implementing pictures as procedures makes these means of combination, you know, both pretty simple and also, I think, elegant. -Dialogue: 0,0:55:45.92,0:55:48.22,Default,,0,0,0,,但是这个不是真正的至理名言\NBut that's not the real punchline. -Dialogue: 0,0:55:49.28,0:55:53.52,Default,,0,0,0,,真正的来自当你用这种语言看待抽象的意义的时候\NThe real punchline comes when you look at the means of abstraction in this language. -Dialogue: 0,0:55:54.70,0:55:56.24,Default,,0,0,0,,因为我们做的什么?\NBecause what have we done? -Dialogue: 0,0:55:56.24,0:56:03.72,Default,,0,0,0,,我们用组合实现了过程\NWe've implemented the means of combination themselves as procedures. -Dialogue: 0,0:56:05.64,0:56:21.62,Default,,0,0,0,,这个的意思是,当我们在这个语言进行抽象的时候,Lisp提供的一切操作过程,都可以用在这个图片语言中\NAnd what that means is that when we go to abstract in this language, everything that Lisp supplies us for manipulating procedures is automatically available to do things in this picture language. -Dialogue: 0,0:56:21.92,0:56:32.80,Default,,0,0,0,,我可以使用的语言不仅仅是Lisp本身的,也包括这种非常优雅的嵌入到Lisp中的语言.\NThe technical term I want to say is not only is this language implemented in Lisp, obviously it is, but the language is nicely embedded in Lisp. -Dialogue: 0,0:56:37.64,0:56:48.86,Default,,0,0,0,,我的意思是,通过这种方式嵌入语言,Lisp的强悍特点就自然的表现出来了,它可以为你做任何事情\NWhat I mean is by embedding the language in this way, 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,Default,,0,0,0,,我的意思是\NAnd what do I mean by that? -Dialogue: 0,0:56:51.68,0:57:07.06,Default,,0,0,0,,比如说,我想做一个图像,它有四个图片做为参数a, b ,c ,d.并且想这样做配置.\NExample: 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. -Dialogue: 0,0:57:12.50,0:57:16.96,Default,,0,0,0,,恩,大家可以叫它,four-pictures或者,four-pict的配置\NWell you might call that, you know, four pictures or something, four-pict configuration. -Dialogue: 0,0:57:16.96,0:57:17.70,Default,,0,0,0,,我如何做到这样的呢?\NHow do I do that? -Dialogue: 0,0:57:17.70,0:57:18.68,Default,,0,0,0,,我可以很容易的做到这些\NWell I can obviously do that. -Dialogue: 0,0:57:18.68,0:57:27.88,Default,,0,0,0,,我就是写一个过程,把b放在d上面,把a放在c上面,然后把这两部分用beside连接起来\NI just write a procedure that takes B above D and A above C and puts those things beside each other. -Dialogue: 0,0:57:28.24,0:57:31.82,Default,,0,0,0,,我天生就有Lisp的能力来做过程组合.\NSo I automatically have Lisp's ability to do procedure composition. -Dialogue: 0,0:57:32.92,0:57:35.82,Default,,0,0,0,,这不需要我专门为图像语言在做什么特殊的事情.\NAnd I didn't have to make that specifically in the picture language. -Dialogue: 0,0:57:35.82,0:57:39.92,Default,,0,0,0,,事实上,这些组合本身就是过程.\NIt's automatic from the fact that the means of combination are themselves procedures. -Dialogue: 0,0:57:40.96,0:57:44.18,Default,,0,0,0,,假设我想做一些更复杂的事情\NOr suppose I wanted to do something a little bit more complicated. -Dialogue: 0,0:57:44.18,0:57:50.08,Default,,0,0,0,,我想为这里的每一个传递一个参数,我可以独立的做旋转90度的操作\NI wanted to put in a parameter so that for each of these, I could independently specify a rotation by 90 degrees. -Dialogue: 0,0:57:50.08,0:57:52.76,Default,,0,0,0,,这只需要我在这个过程中加入一个参数\NThat's just putting a parameter in the procedure. -Dialogue: 0,0:57:52.76,0:57:54.76,Default,,0,0,0,,It's automatically there. -Dialogue: 0,0:57:54.80,0:57:57.84,Default,,0,0,0,,对,它自动就嵌入进去了\NRight, it automatically comes from the embedding. -Dialogue: 0,0:57:58.16,0:58:05.36,Default,,0,0,0,,甚至,假设我想使用递归\NOr even more, suppose I wanted to, you know, use recursion. -Dialogue: 0,0:58:06.16,0:58:10.78,Default,,0,0,0,,我们看一下图片组合的递归\NLet's look at a recursive means of combination on pictures. -Dialogue: 0,0:58:10.78,0:58:19.14,Default,,0,0,0,,我来定义--我们来看,如果你可以理解这个是什么 -- 假设我定义right-push一个图片.\NI 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, -Dialogue: 0,0:58:22.84,0:58:29.80,Default,,0,0,0,,right-push需要一个图片,一个整数N,一个缩放因数A.\Nright-push a picture and some integer N and some scale factor A. -Dialogue: 0,0:58:31.46,0:58:41.22,Default,,0,0,0,,如果n等于0,那么我的定义就返回这个图片本身\NI'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,Default,,0,0,0,,否则,就-- oops,这里是p(教授笔误)\NOtherwise I'm going to put-- oops, name change: P. -Dialogue: 0,0:58:55.88,0:59:18.52,Default,,0,0,0,,否则,我用P,把它放到beside的返回值中,这个返回值递归的进行(right-push P (- n 1) a) .\NOtherwise, 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, -Dialogue: 0,0:59:24.72,0:59:31.12,Default,,0,0,0,,所以,如果n等于0,那么就返回P,否则就对P进行a 倍缩放\Nso 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,Default,,0,0,0,,对不起,我不能把这些代码写成一行---\NI'm sorry I didn't align this right-- -Dialogue: 0,0:59:32.80,0:59:38.50,Default,,0,0,0,,递归的调用(right-push p (- n 1) a),并将结果(递归的)用beside连接\Nrecursively 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,Default,,0,0,0,,这就是一个递归组合方法\NThere's a recursive means of combination. -Dialogue: 0,0:59:43.60,0:59:44.76,Default,,0,0,0,,它看起来像什么呢?\NWhat's that look like? -Dialogue: 0,0:59:44.76,0:59:46.04,Default,,0,0,0,,我们来看看\NWell, here's what it looks like. -Dialogue: 0,0:59:46.04,0:59:56.14,Default,,0,0,0,,这是对George图片应用过程right-pushed 2次,放缩因数是0.75的结果\NThere's George right-pushed against himself twice with a scale factor of 0.75. -Dialogue: 0,0:59:59.26,1:00:00.72,Default,,0,0,0,,这个是从什么地方来的呢?\NWhere'd that come from? -Dialogue: 0,1:00:00.72,1:00:02.34,Default,,0,0,0,,我是如何想象的出来这些递归的呢?\NHow did I get all this fancy recursion? -Dialogue: 0,1:00:02.34,1:00:05.24,Default,,0,0,0,,答案是无意识的,绝对是无意识的\NAnd the answer is just automatic, absolutely automatic. -Dialogue: 0,1:00:05.24,1:00:09.80,Default,,0,0,0,,因为他们都是过程,而且嵌入在(现有的Lisp中),我当然可以定义递归过程\NSince these are procedures, the embedding says, well sure, I can define recursive procedures. -Dialogue: 0,1:00:10.16,1:00:11.80,Default,,0,0,0,,我没有特意去做这个.\NI didn't have to arrange that. -Dialogue: 0,1:00:13.56,1:00:16.42,Default,,0,0,0,,当然,我们可以根据这些做更加复杂的事情\NAnd of course, we can do more complicated things of the same sort. -Dialogue: 0,1:00:16.42,1:00:18.42,Default,,0,0,0,,我可以定义过程叫做up-push.\NI could make something that does an up-push. -Dialogue: 0,1:00:18.42,1:00:22.60,Default,,0,0,0,,对,它可以递归的把图片放在原来的上面\NRight, that sort of goes like this, by recursively putting something above. -Dialogue: 0,1:00:22.60,1:00:26.56,Default,,0,0,0,,或者我也可以用这种策略来做一些其它事情\NOr I could make something that, sort of, was this scheme. -Dialogue: 0,1:00:26.56,1:00:39.30,Default,,0,0,0,,我可以用一个图片开始,然后递归的把它放在原始图片的旁边和上面,这里可以放一些别的\NI might start out with a picture and then, sort of, recursively both push it aside and above, and that might put something there. -Dialogue: 0,1:00:39.30,1:00:44.20,Default,,0,0,0,,然后在这个上面,我递归的做同样的事情。我可以像这样结束它\NAnd then up here I put the same recursive thing, and I might end up with something like this. -Dialogue: 0,1:00:45.40,1:00:52.50,Default,,0,0,0,,对,这个过程比right-push复杂一点,但是也没有复杂很多\NRight, 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,Default,,0,0,0,,我就是做了above和beside,而不仅仅是beside.\NI just do an Above and a Beside, rather than just a Beside. -Dialogue: 0,1:01:01.12,1:01:14.24,Default,,0,0,0,,现在,如果我利用把四个图片放在一起的想法,我确实可以这样做,我把它应用在Q上,这个我们之前定义过\NNow 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, -Dialogue: 0,1:01:15.90,1:01:25.54,Default,,0,0,0,,生成的结果是: 两次"正方形极限".\Nwhat I end up with this is this thing, which is, sort of, the square limit of Q, done twice. -Dialogue: 0,1:01:28.18,1:01:34.74,Default,,0,0,0,,好,我们现在来对比一下Escher的"正方形极限",大家可以看到,这都是基于同样的思想.\NRight, and then we can compare that with Escher's "Square Limit." And you see, it's sort of the same idea. -Dialogue: 0,1:01:34.74,1:01:36.94,Default,,0,0,0,,Escher的图像,当然更加漂亮一些\NEscher's is, of course, much, much prettier. -Dialogue: 0,1:01:36.94,1:01:44.26,Default,,0,0,0,,如果我们会过头看George,\NIf we go back and look at George, right, if we go look at George here-- -Dialogue: 0,1:01:44.26,1:01:49.26,Default,,0,0,0,,看,我最开始使用的是一个非常随意的设计,这张George的图片,并且用这个图片做了一些事情\Nsee, I started with a fairly arbitrary design, this picture of George and did things with it. -Dialogue: 0,1:01:51.04,1:01:53.28,Default,,0,0,0,,对,我们回头看Escher的图片,\NRight, whereas if we go look at the Escher picture, right, -Dialogue: 0,1:01:54.08,1:01:56.14,Default,,0,0,0,,Escher的图片不是随意设计的\Nthe Escher picture is not an arbitrary design. -Dialogue: 0,1:01:56.14,1:02:05.34,Default,,0,0,0,,它是一个非常非常聪明的图案,当你把这个鱼身体旋转,并且对它进行放缩,它变换成另一个非常好看的图像\NIt'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. -Dialogue: 0,1:02:07.40,1:02:11.48,Default,,0,0,0,,当然用George,我没有做像上面做的那些事情\NAnd of course with George, I didn't really do anything like that. -Dialogue: 0,1:02:12.12,1:02:18.64,Default,,0,0,0,,如果我仔细看George, 它也有一些地方可以匹配的,但是不够好。它确实很随意(意思是图片进行变换后很突兀,不能融为一体)\NSo if we look at George, 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:27.54,Default,,0,0,0,,顺便说一下,这是一个非常好的项目,可以写一些过程把一些基本的图形传入进去,就像George一样\NOne very nice project, by the way, would be to write a procedure that could take some basic figure like this George thing -Dialogue: 0,1:02:27.54,1:02:34.14,Default,,0,0,0,,然后开始对图像中的每一条线进行移动,你完全可以获得一个非常漂亮的图案。就像"正方形极限"这个过程一样\Nand start moving the ends of the lines around, so you got a really nice one when you went and did that "Square Limit" process. -Dialogue: 0,1:02:34.14,1:02:36.74,Default,,0,0,0,,这是一个非常值得思考的事情.\NThat'd be a really nice thing to think about. -Dialogue: 0,1:02:38.08,1:02:39.72,Default,,0,0,0,,同时,我还可以进行组合.\NWell so, we can combine things. -Dialogue: 0,1:02:39.72,1:02:41.04,Default,,0,0,0,,我们还可以使用递归过程\NWe can recursive procedures. -Dialogue: 0,1:02:41.04,1:02:43.64,Default,,0,0,0,,我们可以做任何事情,并且他们都是自然而然的\NWe can do all kinds of things, and that's all automatic. -Dialogue: 0,1:02:44.50,1:02:50.44,Default,,0,0,0,,对,重点是,其中的区别仅仅是在一个语言中实现一些东西还是在一个语言中嵌入一些东西\NRight, the important point, the difference between merely implementing something in a language and embedding something in the language, -Dialogue: 0,1:02:50.44,1:02:57.62,Default,,0,0,0,,(嵌入到语言中)可以让你不丢失原有语言的能力,Lisp很强大的地方就是,Lisp是一个强悍的语言可以处理任何特殊问题.\Nso that you don't lose the original power of the language, and what Lisp is great at, see Lisp is a lousy language for doing any particular problem. -Dialogue: 0,1:02:57.62,1:03:02.10,Default,,0,0,0,,把你想要的语言嵌入到Lisp中才是真的好\NWhat 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,Default,,0,0,0,,这才是设计这个方法的真正的力量\NThat's the real power of this approach to design. -Dialogue: 0,1:03:05.44,1:03:06.82,Default,,0,0,0,,当然,我门可以继续下去\NOf course, we can go further. -Dialogue: 0,1:03:06.82,1:03:17.52,Default,,0,0,0,,看,大家看,我们可以用列表做的事情是 -- 抽取做事情的通用方法,就像高阶过程一样\NSee, you saw the other thing that we can do in List is capture general methods of doing things as higher order procedures. -Dialogue: 0,1:03:18.86,1:03:26.72,Default,,0,0,0,,大家刚才跟着我画了这个图像可能已经理解了我的想法:right-push和类似的过程,你放一些东西在上面,上面。。。\NAnd 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 -Dialogue: 0,1:03:26.72,1:03:33.82,Default,,0,0,0,,在这个角落放所有一般化(通用)的想法\Nand this corner push thing are all generalizations of a common kind of idea. -Dialogue: 0,1:03:34.54,1:03:47.52,Default,,0,0,0,,大家仔细想象一下然后自己再实践一下使用复杂的高阶过程,我来给大家展示一下把组合放进去递归的基本思想\NSo 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. -Dialogue: 0,1:03:48.30,1:03:50.90,Default,,0,0,0,,这是一个很好的解惑的例子\NSo here's a good one to puzzle out. -Dialogue: 0,1:03:51.22,1:04:00.70,Default,,0,0,0,,我们用组合方法来定义这个push方法\NWe'll define it what it means to push using a means of combination. -Dialogue: 0,1:04:01.36,1:04:05.06,Default,,0,0,0,,comb是像beside或者above一样的过程\NComb is going to be something like the Beside or Above. -Dialogue: 0,1:04:05.88,1:04:07.06,Default,,0,0,0,,我们来看看它要做什么\NWell what's that going to be. -Dialogue: 0,1:04:07.06,1:04:12.06,Default,,0,0,0,,它是一个过程,记得beside其实也是一个过程\NThat's going to be a procedure, remember what Beside actually was, right. -Dialogue: 0,1:04:13.12,1:04:18.24,Default,,0,0,0,,它使用一个图片,(不)用两个图片和一个缩放因子\NIt took a picture, took two pictures and a scale factor. -Dialogue: 0,1:04:18.48,1:04:24.28,Default,,0,0,0,,利用这个过程,我创造了一个带一个数字,一个图片和一个缩放因子的(过程)\NUsing 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.66,Default,,0,0,0,,我把它定义为right-push.\Nthat I called right-push. -Dialogue: 0,1:04:26.16,1:04:33.66,Default,,0,0,0,,它需要一个图片,一个数字,和一个缩放因子来进行处理\NSo 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,Default,,0,0,0,,我使用了一些重复的操作\NI'm going to do some repeated operation. -Dialogue: 0,1:04:39.12,1:04:59.42,Default,,0,0,0,,我将重复的应用这个过程,这个过程需要一个图片,和一个组合方法,还有原始图片,和在这里的缩放因子\NI'm going to repeatedly apply the procedure which takes a picture and applies the means of combination to the picture and the original picture and the one I took in here and the scale factor, -Dialogue: 0,1:05:02.10,1:05:16.42,Default,,0,0,0,,还有我要循环的次数n.我把整个事情都作用在原始图像上面\Nand I do the thing which repeats this procedure N times, and I apply that whole thing to my original picture. -Dialogue: 0,1:05:19.36,1:05:34.32,Default,,0,0,0,,这里进行循环,这种情况大家还没有看到,是另一个高阶过程需要一个过程和一个数字;它返回另一个过程。返回的过程对这个过程应用n次\NRepeated here, in case you haven't seen it, is another higher order procedure that takes a procedure and a number and returns for you another procedure that applies this procedure N times. -Dialogue: 0,1:05:35.86,1:05:43.22,Default,,0,0,0,,我想大家已经写过循环作为练习了,如果还没有,这是一个非常好的例子用来思考高阶过程\NAnd 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. -Dialogue: 0,1:05:43.72,1:05:46.98,Default,,0,0,0,,但是在任何情况下,这个循环的结果都是我应用到图片的过程\NBut in any case, the result of this repeated is what I apply to picture. -Dialogue: 0,1:05:49.26,1:06:13.30,Default,,0,0,0,,做完这些,可以提取出来的是--我从beside的基本想法到right-push的基本想法。所以做完这个,我可以说,定义right-push来表示对beside做push.\NAnd 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. -Dialogue: 0,1:06:17.42,1:06:26.86,Default,,0,0,0,,如果我说,定义个up-push来对beside做push, 我使用几何公式,或者定义corner-push来push那些相似的东西,比如beside和above,或者我可以push任何东西\NOr 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. -Dialogue: 0,1:06:28.08,1:06:34.76,Default,,0,0,0,,无论如何,如果你对lambda还不太熟悉,这个是一个非常好的练习来让大家体会这其中的意义\NAnyway 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.84,1:06:41.20,Default,,0,0,0,,从这个例子以引申出很多的练习\NOK, well there's a lot to learn from this example. -Dialogue: 0,1:06:42.10,1:06:49.80,Default,,0,0,0,,我想要介绍的主要是在一个语言中嵌入另一个语言\NThe main point I've been welling on is the notion of nicely embedding a language inside another language. -Dialogue: 0,1:06:50.54,1:07:00.42,Default,,0,0,0,,这样所有这门语言的能力,像围绕着Lisp的语言,可以被别的语言访问,可以作为天然的扩展\NRight, so that all the power of this language like Lisp of the surrounding language is still accessible to you and appears as a natural extension of the language that you built. -Dialogue: 0,1:07:00.42,1:07:04.10,Default,,0,0,0,,这个例子很好的展示了这点\NThat's one thing that this example shows very well. -Dialogue: 0,1:07:07.90,1:07:10.94,Default,,0,0,0,,另一个事情是,如果你回头去想\NAnother thing is, if you go back and think about that, -Dialogue: 0,1:07:10.94,1:07:12.28,Default,,0,0,0,,什么是过程什么是数据\Nwhat's procedures and what's data. -Dialogue: 0,1:07:12.28,1:07:16.20,Default,,0,0,0,,到现在, 天啊, 到底发生了什么\NYou 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,Default,,0,0,0,,我的意思是,这是一个过程,它需要一个图片和一个参数\NI mean, this is some procedure, and it takes a picture and an argument, -Dialogue: 0,1:07:19.66,1:07:20.36,Default,,0,0,0,,但是,什么是图片呢\Nand what's a picture. -Dialogue: 0,1:07:20.36,1:07:23.82,Default,,0,0,0,,图片本身,你记得,也是一个过程,它需要一个矩形\NWell, a picture itself, as you remember, was a procedure, and that took a rectangle. -Dialogue: 0,1:07:23.82,1:07:25.82,Default,,0,0,0,,这个矩形是某种抽象\NAnd a rectangle is some abstraction. -Dialogue: 0,1:07:25.82,1:07:33.74,Default,,0,0,0,,我希望到现在大家可以完全丢掉在这个系统中什么是过程,什么是数据的疑问\NAnd 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. -Dialogue: 0,1:07:33.74,1:07:34.78,Default,,0,0,0,,大家可以看到,这没有任何区别\NYou see, there isn't any difference. -Dialogue: 0,1:07:35.08,1:07:36.78,Default,,0,0,0,,真的没有区别\NThere really isn't. -Dialogue: 0,1:07:37.68,1:07:41.84,Default,,0,0,0,,你可以认为有时候图片是一个过程,有时候是数据\NAnd you might think of a picture sometimes as a procedure and sometimes as data, -Dialogue: 0,1:07:41.84,1:07:44.90,Default,,0,0,0,,但是,你知道,那仅仅是让你感觉舒服一点点的方式\Nbut that's just, sort of, you know, making you feel comfortable. -Dialogue: 0,1:07:44.90,1:07:47.64,Default,,0,0,0,,这有一定道理,也没有道理\NIt's really both in some sense or neither in some sense. -Dialogue: 0,1:07:49.92,1:08:14.20,Default,,0,0,0,,还有更普遍关于创造一门语言系统结构的观点:通过看工程师设计的过程来创造一门语言,或者创造一些语言的层级\NOK, 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. -Dialogue: 0,1:08:14.56,1:08:24.90,Default,,0,0,0,,你看,这里有一个方法论,或者我应该说是神话,姑且叫做”软件工程“\NYou see, there's this methodology, or maybe I should say mythology, that's, sort of, charitably called software, quote, engineering. -Dialogue: 0,1:08:25.04,1:08:28.04,Default,,0,0,0,,它所说的很好,你来处理你的任务,\NAll 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,Default,,0,0,0,,你仅仅解决你要做的事情\Nand you figure out exactly what you want to do. -Dialogue: 0,1:08:30.40,1:08:34.54,Default,,0,0,0,,一但你弄明白你要做的东西,你发现它变成了三个子问题,\NAnd once you figure out exactly what you want to do, you find out that it breaks out into three sub-tasks, -Dialogue: 0,1:08:34.54,1:08:38.94,Default,,0,0,0,,然后你开始继续做---你开始处理这些子问题,然后你明确的发现它是什么\Nand you go and you start working on-- 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,Default,,0,0,0,,这些子问题就分裂成三个子问题,你完全把它们处理完.\NAnd 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,Default,,0,0,0,,然后你继续处理剩下的两个,然后你处理这个子问题,然后处理这个.\Nand 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,Default,,0,0,0,,然后你最终完成了你要做的,你回到了这里,然后你开始处理你的第二个子问题\NAnd 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,Default,,0,0,0,,然后把它详细的实现出来\Nand specify that out and work it out. -Dialogue: 0,1:08:53.40,1:08:57.64,Default,,0,0,0,,然后你结束-- 你完成了这个美丽的大厦\NAnd then you end up with-- you end up at the end with this beautiful edifice. -Dialogue: 0,1:08:57.64,1:09:08.24,Default,,0,0,0,,对,你完成了这个不寻常的树,你把问题分成子问题的时候,然后你把这些子问题分成了更小的子问题,然后把他们又分成了更小的问题.\NRight, 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. -Dialogue: 0,1:09:09.88,1:09:18.64,Default,,0,0,0,,然后非常准确的定义了这些节点,他们都是构建这个大厦的完美任务.\NAnd each of these nodes is exactly and precisely defined to do the wonderful, beautiful task to make it fit into the whole edifice, right. -Dialogue: 0,1:09:18.64,1:09:21.14,Default,,0,0,0,,这个就是我说的神话\NThat's this mythology. -Dialogue: 0,1:09:21.14,1:09:26.16,Default,,0,0,0,,只有计算机科学家才可能相信你构建的复杂系统想这个样子\NSee only a computer scientist could possibly believe that you build a complex system like that, right. -Dialogue: 0,1:09:27.86,1:09:32.80,Default,,0,0,0,,我们用Henderson的例子来做对比,\NContrast that with this Henderson example. -Dialogue: 0,1:09:32.80,1:09:34.30,Default,,0,0,0,,它不是这样工作的\NIt didn't work like that. -Dialogue: 0,1:09:35.06,1:09:39.90,Default,,0,0,0,,事实是:这里有一个语言层次的序列\NWhat happened was that there was a sequence of layers of language. -Dialogue: 0,1:09:40.92,1:09:42.18,Default,,0,0,0,,它是什么?\NWhat happened? -Dialogue: 0,1:09:42.18,1:09:48.76,Default,,0,0,0,,这里有一层允许我们构建基本图像\NThere was a layer of a thing that allowed us to build primitive pictures. -Dialogue: 0,1:09:51.50,1:09:56.24,Default,,0,0,0,,这个是基本图像,这就是个语言\NThere's primitive pictures and that was a language. -Dialogue: 0,1:09:56.24,1:09:58.02,Default,,0,0,0,,我这里不多说了\NI didn't say much about it. -Dialogue: 0,1:09:58.02,1:10:05.18,Default,,0,0,0,,我们说一下如何构造George.这是一个语言,这个语言中有向量,线段,点,和它们做存在其中的正方形单元.\NWe 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. -Dialogue: 0,1:10:06.16,1:10:08.74,Default,,0,0,0,,在那的上面\NAnd then on top of that, right, on top of that-- -Dialogue: 0,1:10:09.84,1:10:14.28,Default,,0,0,0,,这个是这个语言的基本图片\Nso this is the language of primitive pictures. -Dialogue: 0,1:10:16.68,1:10:20.56,Default,,0,0,0,,谈论的图片中的线段在这个正方体单元中,\NRight, talking about line segments in particular pictures in the unit square. -Dialogue: 0,1:10:21.40,1:10:23.80,Default,,0,0,0,,在这个上面是整个的语言\NOn top of that was a whole language. -Dialogue: 0,1:10:23.80,1:10:46.50,Default,,0,0,0,,有一个几何组合的语言,几何位置的语言,它讨论的是像above和beside,right-push,rotate这样的东西\NThere was a language of geometric combinators, a language of geometric positions, which talks about things like Above and Beside and right-push and Rotate. -Dialogue: 0,1:10:48.04,1:10:55.70,Default,,0,0,0,,这些事情恰巧与我们在这个语言中谈论的事情有关\NAnd those things, sort of, happened with reference to the things that are talked about in this language. -Dialogue: 0,1:10:55.70,1:11:15.10,Default,,0,0,0,,只要我们愿意,我们可以在这个语言之上创造很多语言规则的组合\NAnd then if we like, we saw that above that there was sort of a language of schemes of combination. -Dialogue: 0,1:11:20.98,1:11:27.88,Default,,0,0,0,,比如push,用一个放缩因子重复的做一个事情.\NFor example, push, which talked about repeatedly doing something over with a scale factor. -Dialogue: 0,1:11:28.38,1:11:34.54,Default,,0,0,0,,我们正在讨论的在那个语言中的东西正是我这里写下来的东西.\NAnd the things that were being discussed in that language were, sort of, the things that happened down here. -Dialogue: 0,1:11:36.06,1:11:47.30,Default,,0,0,0,,在每个层次上都存在已经讨论过的对象,这些对象可以从前一个层级构建出来\NSo what you have is, at each level, the objects that are being talked about are the things that were erected the previous level. -Dialogue: 0,1:11:48.08,1:11:52.06,Default,,0,0,0,,这个和这个有什么区别呢?\NWhat's the difference between this thing and this thing? -Dialogue: 0,1:11:53.10,1:12:05.46,Default,,0,0,0,,答案是:在这个树里,实际上,每一个节点的每一次分解,都是为了特殊的任务在做设计,\NThe 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, -Dialogue: 0,1:12:07.22,1:12:15.12,Default,,0,0,0,,而在这里,你有在每个层级上的完完全全的语言层面的能力.\Nwhereas in the other scheme, what you have is a full range of linguistic power at each level. -Dialogue: 0,1:12:15.82,1:12:22.94,Default,,0,0,0,,看看这里会发生什么 在任何一个层次,这里都不是建立一个特殊的任务\NSee what's happening there, at any level, it's not being set up to do a particular task. -Dialogue: 0,1:12:22.94,1:12:26.74,Default,,0,0,0,,它是建立要做事情整个范围\NIt's being set up to talk about a whole range of things. -Dialogue: 0,1:12:27.50,1:12:35.94,Default,,0,0,0,,结论是:这种设计方法更加健壮,\NThe consequence of that for design is that something that's designed in that method is likely to be more robust, -Dialogue: 0,1:12:36.38,1:12:45.20,Default,,0,0,0,,健壮,我的意思是,在你的描述中做一些改变,可以提取出相关的变化,\Nwhere 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, -Dialogue: 0,1:12:45.20,1:12:56.62,Default,,0,0,0,,使用这种方式,语言可以在下一个层级实现,因为你已经把这个层级的事情做完了\Nin the way that the language is implemented at the next level up, right, because you've made these levels full. -Dialogue: 0,1:12:56.62,1:12:59.66,Default,,0,0,0,,所以你不需要讨论像beside这样的特殊东西\NSo you're not talking about a particular thing like Beside. -Dialogue: 0,1:12:59.66,1:13:07.02,Default,,0,0,0,,你创造了如何去表达事情的词汇,所以如果明确的改变你的定义,\NYou've given yourself a whole vocabulary to express things of that sort, so if you go and change your specifications a little bit, -Dialogue: 0,1:13:07.02,1:13:15.02,Default,,0,0,0,,很可能你的方法论需要随之更改来适应这种变化 因为这种设计不够健壮\Nit'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, -Dialogue: 0,1:13:15.02,1:13:21.80,Default,,0,0,0,,因为如果我在这里改变一些东西 这将影响它向下的路径中的所有分解出来的东西 (影响它)下面的树\Nbecause if I go and change something that's in here, that might affect the entire way that I decomposed everything down, further down the tree. -Dialogue: 0,1:13:23.00,1:13:29.74,Default,,0,0,0,,最大的不同就是分解 语言分层级还是严格的分层\NRight, so very big difference in outlook in decomposition, levels of language rather than, sort of, a strict hierarchy. -Dialogue: 0,1:13:30.22,1:13:38.74,Default,,0,0,0,,不仅这个如此 当你有一个多层的语言的时候 你会为不同的层次起不同的词汇\NNot only that, but when you have levels of language you've given yourself a different vocabularies for talking about the design at different levels. -Dialogue: 0,1:13:38.74,1:13:48.68,Default,,0,0,0,,所以如果我们回头再看一次George 如果我想改变这个图像George 看 我有完全不同的方式来表述这个变化\NSo 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. -Dialogue: 0,1:13:48.68,1:13:56.08,Default,,0,0,0,,比如 我也许想要在基本的设计中修改一些向量的端点\NLike 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,Default,,0,0,0,,这个变化在最低的层次\NThat's a change that I would discuss at the lowest level. -Dialogue: 0,1:14:00.76,1:14:02.76,Default,,0,0,0,,我可以说端点在某个地方\NI would say the endpoint is somewhere else. -Dialogue: 0,1:14:03.10,1:14:10.94,Default,,0,0,0,,或许我可以上来说 我想做的下一个事情是:这个重复的元素 我想用其他方式来实现\NOr 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. -Dialogue: 0,1:14:10.94,1:14:13.84,Default,,0,0,0,,我可能想把一个放缩因子放入那个beside中\NI might want to put a scale factor in that Beside. -Dialogue: 0,1:14:13.84,1:14:19.34,Default,,0,0,0,,这个变化我可以在为下一个层次的设计时讨论---组合的层次\NThat'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:30.64,Default,,0,0,0,,或者我想说 我想改变这个基本的方法 我用这个模式然后做一些递归分解 也许不会 #TBD 后面的不知道怎么翻译\NOr 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. -Dialogue: 0,1:14:31.16,1:14:34.18,Default,,0,0,0,,这个会改变我所讨论的最高的层次\NThat would be a change that I would discuss at the highest level. -Dialogue: 0,1:14:34.18,1:14:42.48,Default,,0,0,0,,因为我是用这种方式构建系统的 我有全部的词汇来用不同的方式实现(我说的)并且有很大的灵活性来让我决定那个更合适\NAnd 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. -Dialogue: 0,1:14:44.56,1:14:54.38,Default,,0,0,0,,在软件方法学中的一个很大的不同是--来自于Lisp 全部来自于概念\NOK, well that's sort of a big point about the difference in software methodology that comes out from Lisp, and it all comes, again, out of the notion that really, -Dialogue: 0,1:14:54.38,1:14:59.62,Default,,0,0,0,,在设计的过程中 没有那么多的实现的程序作为实现的语言\Nthe design process is not so much implementing programs as implementing languages. -Dialogue: 0,1:14:59.62,1:15:04.02,Default,,0,0,0,,这就是Lisp的力量 好的 谢谢\NAnd that's really the powerful of Lisp. OK, thank you. +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 diff --git a/Ass/lec3a_chn.ass b/Ass/lec3a_chn.ass new file mode 100644 index 0000000..01c9b4a --- /dev/null +++ b/Ass/lec3a_chn.ass @@ -0,0 +1,953 @@ +[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,,这只是另外一种方式v一个语法糖 +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,,一部分比例是A 另一部分是1-A +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 diff --git a/Ass/lec3a_eng.ass b/Ass/lec3a_eng.ass new file mode 100644 index 0000000..28f0735 --- /dev/null +++ b/Ass/lec3a_eng.ass @@ -0,0 +1,956 @@ +[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,, diff --git a/Tools/separate.rb b/Tools/separate.rb index 5c44b0a..f936648 100755 --- a/Tools/separate.rb +++ b/Tools/separate.rb @@ -15,7 +15,7 @@ # 换行符,由于文件比较混乱,有时需要自行调整 # 如有问题,可以尝试调整为 \n、\r、\r\n中的其它值 -newline = "\r\n" +newline = "\n" open(ARGV[0]).each_line do |line| if line == newline