代码拉取完成,页面将自动刷新
[Script Info]
; Script generated by Aegisub 3.2.2
; http://www.aegisub.org/
Title: EN Aegisub file
ScriptType: v4.00+
WrapStyle: 0
ScaledBorderAndShadow: yes
YCbCr Matrix: TV.601
PlayResX: 640
PlayResY: 480
[Aegisub Project Garbage]
Audio File: ../../../../Movies/lec6a_480_muxed.mp4
Video File: ../../../../Movies/lec6a_480_muxed.mp4
Video AR Mode: 4
Video AR Value: 1.333333
Video Zoom Percent: 2.000000
Video Position: 556
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1
Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1
Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1
Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1
Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:18.55,0:00:21.84,EN,,0,0,0,,PROFESSOR: Well, last time Gerry really let the cat out of the bag.
Dialogue: 0,0:00:22.49,0:00:24.60,EN,,0,0,0,,He introduced the idea of assignment.
Dialogue: 0,0:00:26.35,0:00:33.61,EN,,0,0,0,,Assignment and state.
Dialogue: 0,0:00:37.48,0:00:40.03,EN,,0,0,0,,And as we started to see, the implications
Dialogue: 0,0:00:40.72,0:00:43.16,EN,,0,0,0,,of introducing assignment and state into the language
Dialogue: 0,0:00:43.16,0:00:44.41,EN,,0,0,0,,are absolutely frightening.
Dialogue: 0,0:00:45.08,0:00:48.62,EN,,0,0,0,,First of all, the substitution model of evaluation breaks down.
Dialogue: 0,0:00:49.13,0:00:52.48,EN,,0,0,0,,And we have to use this much more complicated environment model
Dialogue: 0,0:00:52.48,0:00:54.27,EN,,0,0,0,,this very mechanistic thing with diagrams,
Dialogue: 0,0:00:54.28,0:00:57.24,EN,,0,0,0,,even to say what statements in the programming language mean.
Dialogue: 0,0:00:58.46,0:01:00.12,EN,,0,0,0,,And that's not a mere technical point.
Dialogue: 0,0:01:00.26,0:01:03.28,EN,,0,0,0,,See, it's not that we had this particular substitution model and,
Dialogue: 0,0:01:03.60,0:01:05.68,EN,,0,0,0,,well, it doesn't quite work, so we have to do something else.
Dialogue: 0,0:01:05.71,0:01:09.79,EN,,0,0,0,,It's that nothing like the substitution model can work.
Dialogue: 0,0:01:10.73,0:01:13.32,EN,,0,0,0,,Because suddenly, a variable
Dialogue: 0,0:01:14.12,0:01:16.92,EN,,0,0,0,,is not just something that stands for a value.
Dialogue: 0,0:01:17.95,0:01:21.76,EN,,0,0,0,,A variable now has to somehow specify a place
Dialogue: 0,0:01:22.40,0:01:23.34,EN,,0,0,0,,that holds a value.
Dialogue: 0,0:01:23.63,0:01:26.14,EN,,0,0,0,,And the value that's in that place can change.
Dialogue: 0,0:01:30.28,0:01:34.09,EN,,0,0,0,,Or for instance, an expression like f of x
Dialogue: 0,0:01:37.36,0:01:39.64,EN,,0,0,0,,might have a side effect in it.
Dialogue: 0,0:01:40.41,0:01:42.60,EN,,0,0,0,,So if we say f of x and it has some value,
Dialogue: 0,0:01:43.18,0:01:45.34,EN,,0,0,0,,and then later we say f of x again,
Dialogue: 0,0:01:47.24,0:01:48.43,EN,,0,0,0,,we might get a different value
Dialogue: 0,0:01:48.86,0:01:49.74,EN,,0,0,0,,depending on the order.
Dialogue: 0,0:01:49.76,0:01:52.14,EN,,0,0,0,,So suddenly, we have to think not only about values
Dialogue: 0,0:01:52.52,0:01:53.60,EN,,0,0,0,,but about time.
Dialogue: 0,0:01:57.97,0:01:59.98,EN,,0,0,0,,And then things like pairs
Dialogue: 0,0:02:00.65,0:02:02.52,EN,,0,0,0,,are no longer just their CARs and their CDRs.
Dialogue: 0,0:02:02.52,0:02:05.61,EN,,0,0,0,,A pair now is not quite its CAR and its CDR.
Dialogue: 0,0:02:05.80,0:02:07.05,EN,,0,0,0,,It's rather its identity.
Dialogue: 0,0:02:08.44,0:02:11.65,EN,,0,0,0,,So a pair has identity.
Dialogue: 0,0:02:11.65,0:02:12.59,EN,,0,0,0,,It's an object.
Dialogue: 0,0:02:21.33,0:02:25.15,EN,,0,0,0,,And two pairs that have the same CAR and CDR
Dialogue: 0,0:02:25.40,0:02:27.05,EN,,0,0,0,,well, might be the same or different,
Dialogue: 0,0:02:27.87,0:02:30.51,EN,,0,0,0,,because suddenly we have to worry about sharing.
Dialogue: 0,0:02:34.96,0:02:39.45,EN,,0,0,0,,So all of these things enter as soon as we introduce assignment.
Dialogue: 0,0:02:40.48,0:02:43.98,EN,,0,0,0,,See, this is a really far cry from where we started with substitution.
Dialogue: 0,0:02:45.04,0:02:48.91,EN,,0,0,0,,It's a technically harder way of looking at things
Dialogue: 0,0:02:48.94,0:02:53.45,EN,,0,0,0,,because we have to think more mechanistically about our programming language.
Dialogue: 0,0:02:53.47,0:02:55.34,EN,,0,0,0,,We can't just think about it as mathematics.
Dialogue: 0,0:02:55.71,0:02:58.60,EN,,0,0,0,,It's philosophically harder,
Dialogue: 0,0:02:59.15,0:03:00.65,EN,,0,0,0,,because suddenly there are all these funny issues
Dialogue: 0,0:03:00.67,0:03:02.38,EN,,0,0,0,,what does it mean that something changes
Dialogue: 0,0:03:02.38,0:03:03.77,EN,,0,0,0,,or that two things are the same.
Dialogue: 0,0:03:03.84,0:03:06.83,EN,,0,0,0,,And also, it's programming harder, because
Dialogue: 0,0:03:07.47,0:03:08.54,EN,,0,0,0,,as Gerry showed last time,
Dialogue: 0,0:03:08.56,0:03:12.20,EN,,0,0,0,,there are all these bugs having to do with bad sequencing and aliasing
Dialogue: 0,0:03:12.22,0:03:16.19,EN,,0,0,0,,that just don't exist in a language where we don't worry about objects.
Dialogue: 0,0:03:18.21,0:03:21.20,EN,,0,0,0,,Well, how'd we get into this mess?
Dialogue: 0,0:03:24.01,0:03:27.20,EN,,0,0,0,,Remember what we did, the reason we got into this is
Dialogue: 0,0:03:27.40,0:03:31.47,EN,,0,0,0,,because we were looking to build modular systems.
Dialogue: 0,0:03:35.15,0:03:37.69,EN,,0,0,0,,We wanted to build systems that
Dialogue: 0,0:03:38.09,0:03:41.04,EN,,0,0,0,,that fall apart into chunks that seem natural.
Dialogue: 0,0:03:42.76,0:03:43.82,EN,,0,0,0,,So for instance,
Dialogue: 0,0:03:44.06,0:03:46.11,EN,,0,0,0,,we want to take a random number generator
Dialogue: 0,0:03:46.22,0:03:49.40,EN,,0,0,0,,and package up the state of that random number generator inside of it
Dialogue: 0,0:03:50.25,0:03:53.71,EN,,0,0,0,,so that we can separate the idea of picking random numbers
Dialogue: 0,0:03:54.65,0:03:57.79,EN,,0,0,0,,from the general Monte Carlo strategy of estimating something
Dialogue: 0,0:03:58.65,0:04:01.52,EN,,0,0,0,,and separate that from the particular way that you
Dialogue: 0,0:04:01.90,0:04:05.74,EN,,0,0,0,,work with random numbers in that formula developed by Cesaro for pi.
Dialogue: 0,0:04:06.80,0:04:07.92,EN,,0,0,0,,And similarly,
Dialogue: 0,0:04:09.61,0:04:11.74,EN,,0,0,0,,when we go off and construct some models of things,
Dialogue: 0,0:04:12.35,0:04:16.01,EN,,0,0,0,,Ah, if we go off and model a system that we see in the real world,
Dialogue: 0,0:04:17.31,0:04:19.42,EN,,0,0,0,,we'd like our program to break into natural pieces,
Dialogue: 0,0:04:19.44,0:04:20.52,EN,,0,0,0,,pieces that mirror
Dialogue: 0,0:04:21.05,0:04:23.16,EN,,0,0,0,,the parts of the system that we see in the real world.
Dialogue: 0,0:04:24.90,0:04:27.56,EN,,0,0,0,,So for example, if we look at a digital circuit,
Dialogue: 0,0:04:28.36,0:04:29.18,EN,,0,0,0,,we say, gee,
Dialogue: 0,0:04:30.44,0:04:31.44,EN,,0,0,0,,there's a circuit
Dialogue: 0,0:04:32.08,0:04:35.16,EN,,0,0,0,,and it has a piece and it has another piece.
Dialogue: 0,0:04:40.10,0:04:43.58,EN,,0,0,0,,And these different pieces sort of have identity.
Dialogue: 0,0:04:43.58,0:04:44.59,EN,,0,0,0,,They have state.
Dialogue: 0,0:04:45.55,0:04:47.13,EN,,0,0,0,,And the state sits on these wires.
Dialogue: 0,0:04:48.58,0:04:50.22,EN,,0,0,0,,And we think of this piece as an object
Dialogue: 0,0:04:50.49,0:04:51.93,EN,,0,0,0,,that's different from that as an object.
Dialogue: 0,0:04:52.54,0:04:53.85,EN,,0,0,0,,And when we watch the system change,
Dialogue: 0,0:04:53.87,0:04:55.40,EN,,0,0,0,,we think about a signal coming in here
Dialogue: 0,0:04:55.63,0:04:58.41,EN,,0,0,0,,changing a state that might be here and going here
Dialogue: 0,0:04:58.67,0:05:00.75,EN,,0,0,0,,and interacting with a state that might be stored there,
Dialogue: 0,0:05:01.24,0:05:02.17,EN,,0,0,0,,and so on and so on.
Dialogue: 0,0:05:06.86,0:05:11.24,EN,,0,0,0,,So what we'd like is we'd like to build in the computer
Dialogue: 0,0:05:12.76,0:05:14.36,EN,,0,0,0,,systems that fall into pieces
Dialogue: 0,0:05:14.68,0:05:17.87,EN,,0,0,0,,that fall into pieces that mirror our view of reality,
Dialogue: 0,0:05:17.88,0:05:19.87,EN,,0,0,0,,of the way that the actual systems we're modeling
Dialogue: 0,0:05:19.88,0:05:20.91,EN,,0,0,0,,seem to fall into pieces.
Dialogue: 0,0:05:23.20,0:05:23.48,EN,,0,0,0,,Well,
Dialogue: 0,0:05:25.74,0:05:28.99,EN,,0,0,0,,maybe the reason that building systems like this
Dialogue: 0,0:05:28.99,0:05:31.50,EN,,0,0,0,,seems to introduce such technical complications
Dialogue: 0,0:05:31.52,0:05:32.75,EN,,0,0,0,,has nothing to do with computers.
Dialogue: 0,0:05:33.61,0:05:35.60,EN,,0,0,0,,See, maybe the real reason
Dialogue: 0,0:05:36.70,0:05:38.65,EN,,0,0,0,,that we pay such a price to write programs
Dialogue: 0,0:05:38.67,0:05:40.94,EN,,0,0,0,,that mirror our view of reality
Dialogue: 0,0:05:41.52,0:05:43.13,EN,,0,0,0,,is that we have the wrong view of reality.
Dialogue: 0,0:05:44.55,0:05:46.75,EN,,0,0,0,,See, maybe time is just an illusion,
Dialogue: 0,0:05:47.26,0:05:48.60,EN,,0,0,0,,and nothing ever changes.
Dialogue: 0,0:05:50.15,0:05:51.71,EN,,0,0,0,,See, for example, if I take this chalk,
Dialogue: 0,0:05:52.44,0:05:53.77,EN,,0,0,0,,and we say, gee, this is an object
Dialogue: 0,0:05:54.01,0:05:54.99,EN,,0,0,0,,and it has a state.
Dialogue: 0,0:05:55.82,0:05:59.29,EN,,0,0,0,,At each moment it has a position and a velocity.
Dialogue: 0,0:05:59.71,0:06:01.48,EN,,0,0,0,,And if we do something, that state can change.
Dialogue: 0,0:06:04.34,0:06:07.37,EN,,0,0,0,,But if you studied any relativity, for instance,
Dialogue: 0,0:06:07.74,0:06:09.71,EN,,0,0,0,,you know that you don't think of the path of that chalk
Dialogue: 0,0:06:09.72,0:06:11.34,EN,,0,0,0,,as something that goes on instant by instant.
Dialogue: 0,0:06:11.34,0:06:14.38,EN,,0,0,0,,It's more insightful to think of that whole chalk's existence
Dialogue: 0,0:06:14.41,0:06:15.64,EN,,0,0,0,,as a path in space-time.
Dialogue: 0,0:06:16.02,0:06:17.37,EN,,0,0,0,,that's all splayed out.
Dialogue: 0,0:06:17.87,0:06:19.84,EN,,0,0,0,,There aren't individual positions and velocities.
Dialogue: 0,0:06:19.84,0:06:23.80,EN,,0,0,0,,There's just its unchanging existence in space-time.
Dialogue: 0,0:06:24.64,0:06:26.51,EN,,0,0,0,,Similarly, if we look at this electrical system,
Dialogue: 0,0:06:27.69,0:06:30.43,EN,,0,0,0,,if we imagine this electrical system is implementing
Dialogue: 0,0:06:30.59,0:06:33.96,EN,,0,0,0,,sort of signal processing system,
Dialogue: 0,0:06:34.36,0:06:36.68,EN,,0,0,0,,the signal processing engineer who put that thing together
Dialogue: 0,0:06:36.75,0:06:38.60,EN,,0,0,0,,doesn't think of it as, well,
Dialogue: 0,0:06:38.96,0:06:41.40,EN,,0,0,0,,at each instance there's a voltage coming in.
Dialogue: 0,0:06:41.49,0:06:43.16,EN,,0,0,0,,And that translates into something.
Dialogue: 0,0:06:43.34,0:06:45.52,EN,,0,0,0,,And that affects the state over here,
Dialogue: 0,0:06:45.53,0:06:46.81,EN,,0,0,0,,which changes the state over here.
Dialogue: 0,0:06:46.81,0:06:50.11,EN,,0,0,0,,Nobody putting together a signal processing system thinks about it like that.
Dialogue: 0,0:06:50.42,0:06:51.84,EN,,0,0,0,,Instead, you say there's this signal
Dialogue: 0,0:06:54.04,0:06:58.06,EN,,0,0,0,,that's splayed out over time.
Dialogue: 0,0:06:58.06,0:06:59.48,EN,,0,0,0,,And if this is acting as a filter,
Dialogue: 0,0:07:00.20,0:07:04.04,EN,,0,0,0,,this whole thing transforms this whole thing
Dialogue: 0,0:07:04.28,0:07:07.04,EN,,0,0,0,,for some sort of other output.
Dialogue: 0,0:07:09.57,0:07:11.28,EN,,0,0,0,,You don't think of it as what's happening
Dialogue: 0,0:07:11.28,0:07:13.29,EN,,0,0,0,,instant by instant as the state of these things.
Dialogue: 0,0:07:14.16,0:07:17.32,EN,,0,0,0,,And somehow you think of this box as a whole thing,
Dialogue: 0,0:07:17.32,0:07:20.16,EN,,0,0,0,,not as little pieces sending messages of state
Dialogue: 0,0:07:20.40,0:07:21.96,EN,,0,0,0,,to each other at particular instants.
Dialogue: 0,0:07:28.25,0:07:29.36,EN,,0,0,0,,Well, today we're going to look at
Dialogue: 0,0:07:29.39,0:07:31.13,EN,,0,0,0,,another way to decompose systems
Dialogue: 0,0:07:31.36,0:07:35.45,EN,,0,0,0,,that's more like the signal processing engineer's view of the world
Dialogue: 0,0:07:35.69,0:07:38.96,EN,,0,0,0,,than it is like thinking about objects that communicate sending messages.
Dialogue: 0,0:07:41.13,0:07:43.74,EN,,0,0,0,,That's called stream processing.
Dialogue: 0,0:07:54.57,0:07:58.96,EN,,0,0,0,,And we're going to start by showing
Dialogue: 0,0:08:00.59,0:08:04.16,EN,,0,0,0,,by showing how we can make our programs more uniform
Dialogue: 0,0:08:05.15,0:08:06.54,EN,,0,0,0,,and see a lot more commonality
Dialogue: 0,0:08:06.65,0:08:09.88,EN,,0,0,0,,if we throw out of these programs
Dialogue: 0,0:08:10.81,0:08:12.30,EN,,0,0,0,,what you might say is a
Dialogue: 0,0:08:12.35,0:08:15.12,EN,,0,0,0,,inordinate concern with worrying about time.
Dialogue: 0,0:08:16.89,0:08:20.22,EN,,0,0,0,,Let me start by comparing two procedures.
Dialogue: 0,0:08:23.55,0:08:25.69,EN,,0,0,0,,The first one does this.
Dialogue: 0,0:08:25.69,0:08:27.77,EN,,0,0,0,,We imagine that there's a tree.
Dialogue: 0,0:08:30.40,0:08:32.14,EN,,0,0,0,,Say there's a tree of integers.
Dialogue: 0,0:08:33.28,0:08:34.42,EN,,0,0,0,,It's a binary tree.
Dialogue: 0,0:08:36.12,0:08:36.97,EN,,0,0,0,,Say 1.
Dialogue: 0,0:08:39.10,0:08:40.23,EN,,0,0,0,,So it looks like this.
Dialogue: 0,0:08:40.23,0:08:42.92,EN,,0,0,0,,And there's integers in each of the nodes.
Dialogue: 0,0:08:45.18,0:08:47.80,EN,,0,0,0,,And what we would like to compute is
Dialogue: 0,0:08:48.67,0:08:51.56,EN,,0,0,0,,for each odd number sitting here,
Dialogue: 0,0:08:52.30,0:08:55.10,EN,,0,0,0,,we'd like to find the square and then sum up all those squares.
Dialogue: 0,0:08:57.05,0:08:59.48,EN,,0,0,0,,Well, that should be a familiar kind of thing.
Dialogue: 0,0:08:59.48,0:09:01.95,EN,,0,0,0,,There's a recursive strategy for doing it.
Dialogue: 0,0:09:02.93,0:09:04.35,EN,,0,0,0,,We look at each leaf, and either
Dialogue: 0,0:09:04.56,0:09:06.68,EN,,0,0,0,,it's going to contribute the square of the number if it's odd
Dialogue: 0,0:09:06.70,0:09:07.77,EN,,0,0,0,,or 0 if it's even.
Dialogue: 0,0:09:08.68,0:09:12.11,EN,,0,0,0,,And then recursively, we can say at each tree
Dialogue: 0,0:09:12.65,0:09:13.84,EN,,0,0,0,,the sum of all of them is
Dialogue: 0,0:09:13.92,0:09:15.93,EN,,0,0,0,,the sum coming from the right branch and the left branch,
Dialogue: 0,0:09:16.25,0:09:17.64,EN,,0,0,0,,and recursively down through the nodes.
Dialogue: 0,0:09:17.64,0:09:18.70,EN,,0,0,0,,And that's a familiar way of
Dialogue: 0,0:09:19.26,0:09:20.36,EN,,0,0,0,,thinking about programming.
Dialogue: 0,0:09:20.36,0:09:22.59,EN,,0,0,0,,Let's actually look at that on the slide.
Dialogue: 0,0:09:23.82,0:09:26.75,EN,,0,0,0,,We say to sum the odd squares in a tree,
Dialogue: 0,0:09:27.37,0:09:29.36,EN,,0,0,0,,there's a test. Either it's a leaf node,
Dialogue: 0,0:09:29.82,0:09:31.95,EN,,0,0,0,,and we're going to check to see if it's an integer,
Dialogue: 0,0:09:32.88,0:09:36.38,EN,,0,0,0,,and then either it's odd, in which we take the square, or else it's 0.
Dialogue: 0,0:09:37.16,0:09:38.99,EN,,0,0,0,,And then the sum of the whole thing
Dialogue: 0,0:09:39.21,0:09:42.12,EN,,0,0,0,,is the sum coming from the left branch and the right branch.
Dialogue: 0,0:09:46.34,0:09:50.56,EN,,0,0,0,,OK, well, let me contrast that with a second problem.
Dialogue: 0,0:09:51.56,0:09:53.68,EN,,0,0,0,,Suppose I give you an integer n,
Dialogue: 0,0:09:54.73,0:09:57.88,EN,,0,0,0,,and then some function to compute of the first of each integer
Dialogue: 0,0:09:57.93,0:09:58.83,EN,,0,0,0,,1 through n.
Dialogue: 0,0:09:59.10,0:10:01.08,EN,,0,0,0,,And then I want to collect together in a list
Dialogue: 0,0:10:01.28,0:10:04.65,EN,,0,0,0,,all those function values that satisfy some property.
Dialogue: 0,0:10:05.60,0:10:06.88,EN,,0,0,0,,That's a general kind of thing.
Dialogue: 0,0:10:06.88,0:10:07.98,EN,,0,0,0,,Let's say to be specific,
Dialogue: 0,0:10:08.62,0:10:10.48,EN,,0,0,0,,let's imagine that for each integer, k,
Dialogue: 0,0:10:10.65,0:10:12.51,EN,,0,0,0,,we're going to compute the k Fibonacci number.
Dialogue: 0,0:10:14.21,0:10:16.27,EN,,0,0,0,,And then we'll see which of those are odd
Dialogue: 0,0:10:16.83,0:10:18.40,EN,,0,0,0,,and assemble those into a list.
Dialogue: 0,0:10:19.05,0:10:20.71,EN,,0,0,0,,So here's a procedure that does that.
Dialogue: 0,0:10:23.73,0:10:26.24,EN,,0,0,0,,Find the odd Fibonacci numbers among the first n.
Dialogue: 0,0:10:26.24,0:10:28.91,EN,,0,0,0,,And here is a standard loop the way we've been writing it.
Dialogue: 0,0:10:28.91,0:10:29.82,EN,,0,0,0,,This is a recursion.
Dialogue: 0,0:10:30.80,0:10:31.79,EN,,0,0,0,,It's a loop on k,
Dialogue: 0,0:10:32.03,0:10:34.35,EN,,0,0,0,,and says if k is bigger than n, it's the empty list.
Dialogue: 0,0:10:35.13,0:10:37.36,EN,,0,0,0,,Otherwise we compute the k-th Fibonacci number,
Dialogue: 0,0:10:37.44,0:10:38.06,EN,,0,0,0,,call that f.
Dialogue: 0,0:10:40.37,0:10:42.84,EN,,0,0,0,,If it's odd, we CONS it on
Dialogue: 0,0:10:43.76,0:10:46.01,EN,,0,0,0,,to the list starting with the next one.
Dialogue: 0,0:10:47.69,0:10:50.12,EN,,0,0,0,,And otherwise, we just take the next one.
Dialogue: 0,0:10:50.73,0:10:53.00,EN,,0,0,0,,And this is the standard way we've been writing iterative loops.
Dialogue: 0,0:10:53.00,0:10:55.56,EN,,0,0,0,,And we start off calling that loop with 1.
Dialogue: 0,0:10:57.58,0:11:00.06,EN,,0,0,0,,OK, so there are two procedures.
Dialogue: 0,0:11:01.60,0:11:02.90,EN,,0,0,0,,Those procedures look very different.
Dialogue: 0,0:11:02.90,0:11:04.20,EN,,0,0,0,,They have very different structures.
Dialogue: 0,0:11:04.25,0:11:06.89,EN,,0,0,0,,Yet from a certain point of view,
Dialogue: 0,0:11:06.92,0:11:09.61,EN,,0,0,0,,those procedures are really doing very much the same thing.
Dialogue: 0,0:11:11.33,0:11:14.67,EN,,0,0,0,,So if I was talking like a signal processing engineer,
Dialogue: 0,0:11:14.70,0:11:16.81,EN,,0,0,0,,what I might say
Dialogue: 0,0:11:18.24,0:11:26.76,EN,,0,0,0,,the first procedure enumerates the leaves of a tree.
Dialogue: 0,0:11:31.16,0:11:34.56,EN,,0,0,0,,And then we can think of a signal coming out of that, which is all the leaves.
Dialogue: 0,0:11:35.33,0:11:43.39,EN,,0,0,0,,We'll filter them to see which ones are odd,
Dialogue: 0,0:11:43.58,0:11:44.94,EN,,0,0,0,,put them through some kind of filter.
Dialogue: 0,0:11:45.19,0:11:47.79,EN,,0,0,0,,We'll then put them through a kind of transducer.
Dialogue: 0,0:11:49.20,0:11:51.69,EN,,0,0,0,,And for each one of those things, we'll take the square.
Dialogue: 0,0:11:54.44,0:11:57.44,EN,,0,0,0,,And then we'll accumulate all of those.
Dialogue: 0,0:11:58.29,0:12:00.04,EN,,0,0,0,,We'll accumulate them by sticking them together
Dialogue: 0,0:12:00.35,0:12:03.37,EN,,0,0,0,,with addition starting from 0.
Dialogue: 0,0:12:07.14,0:12:08.21,EN,,0,0,0,,That's the first program.
Dialogue: 0,0:12:08.21,0:12:09.18,EN,,0,0,0,,The second program,
Dialogue: 0,0:12:09.24,0:12:11.21,EN,,0,0,0,,I can describe in a very, very similar way.
Dialogue: 0,0:12:11.78,0:12:13.42,EN,,0,0,0,,I'll say, we'll enumerate
Dialogue: 0,0:12:15.80,0:12:19.10,EN,,0,0,0,,the numbers on this interval, for the interval 1 through n.
Dialogue: 0,0:12:22.50,0:12:24.40,EN,,0,0,0,,We'll, for each one,
Dialogue: 0,0:12:25.45,0:12:26.92,EN,,0,0,0,,compute the Fibonacci number,
Dialogue: 0,0:12:27.79,0:12:29.27,EN,,0,0,0,,put them through a transducer.
Dialogue: 0,0:12:29.27,0:12:30.78,EN,,0,0,0,,We'll then take the result of that,
Dialogue: 0,0:12:31.31,0:12:34.20,EN,,0,0,0,,and we'll filter it for oddness.
Dialogue: 0,0:12:36.27,0:12:39.24,EN,,0,0,0,,And then we'll take those and put them into an accumulator.
Dialogue: 0,0:12:39.35,0:12:40.56,EN,,0,0,0,,This time we'll build up a list,
Dialogue: 0,0:12:40.78,0:12:42.17,EN,,0,0,0,,so we'll accumulate with CONS
Dialogue: 0,0:12:42.59,0:12:43.77,EN,,0,0,0,,starting from the empty list.
Dialogue: 0,0:12:47.11,0:12:49.80,EN,,0,0,0,,So this way of looking at the program
Dialogue: 0,0:12:49.85,0:12:51.84,EN,,0,0,0,,makes the two seem very, very similar.
Dialogue: 0,0:12:51.90,0:12:52.84,EN,,0,0,0,,The problem is
Dialogue: 0,0:12:53.20,0:12:56.49,EN,,0,0,0,,that that commonality is completely obscured
Dialogue: 0,0:12:56.64,0:12:58.05,EN,,0,0,0,,when we look at the procedures we wrote.
Dialogue: 0,0:12:58.05,0:13:01.44,EN,,0,0,0,,Let's go back and look at some odd squares again,
Dialogue: 0,0:13:02.22,0:13:04.64,EN,,0,0,0,,and say things like, where's the enumerator?
Dialogue: 0,0:13:06.35,0:13:08.14,EN,,0,0,0,,Where's the enumerator in this program?
Dialogue: 0,0:13:08.14,0:13:10.52,EN,,0,0,0,,Well, it's not in one place.
Dialogue: 0,0:13:11.02,0:13:15.47,EN,,0,0,0,,It's a little bit in this leaf-node test,
Dialogue: 0,0:13:16.43,0:13:17.16,EN,,0,0,0,,which is going to stop.
Dialogue: 0,0:13:17.16,0:13:20.06,EN,,0,0,0,,It's a little bit in the recursive structure of the thing itself.
Dialogue: 0,0:13:23.15,0:13:24.12,EN,,0,0,0,,Where's the accumulator?
Dialogue: 0,0:13:24.12,0:13:25.68,EN,,0,0,0,,The accumulator isn't in one place either.
Dialogue: 0,0:13:25.68,0:13:30.73,EN,,0,0,0,,It's partly in this 0 and partly in this plus.
Dialogue: 0,0:13:32.00,0:13:34.51,EN,,0,0,0,,Right? It's not there as a thing that we can look at.
Dialogue: 0,0:13:34.51,0:13:39.05,EN,,0,0,0,,Similarly, if we look at odd Fibs,
Dialogue: 0,0:13:39.05,0:13:42.80,EN,,0,0,0,,that's also, in some sense, an enumerator and an accumulator,
Dialogue: 0,0:13:42.80,0:13:44.01,EN,,0,0,0,,but it looks very different.
Dialogue: 0,0:13:44.62,0:13:50.09,EN,,0,0,0,,Because partly, the enumerator is here in this greater than sign in the test.
Dialogue: 0,0:13:50.38,0:13:52.84,EN,,0,0,0,,And partly it's in this whole recursive structure in the loop,
Dialogue: 0,0:13:53.18,0:13:54.24,EN,,0,0,0,,and the way that we call it.
Dialogue: 0,0:13:55.68,0:13:56.32,EN,,0,0,0,,And then similarly,
Dialogue: 0,0:13:56.52,0:13:58.76,EN,,0,0,0,,that's also mixed up in there with the accumulator,
Dialogue: 0,0:13:58.91,0:14:00.12,EN,,0,0,0,,which is partly over there
Dialogue: 0,0:14:00.41,0:14:01.40,EN,,0,0,0,,and partly over there.
Dialogue: 0,0:14:03.60,0:14:06.08,EN,,0,0,0,,So these very, very natural pieces,
Dialogue: 0,0:14:08.73,0:14:12.65,EN,,0,0,0,,these very natural boxes here don't appear in our programs.
Dialogue: 0,0:14:13.26,0:14:14.36,EN,,0,0,0,,Because they're kind of mixed up.
Dialogue: 0,0:14:14.36,0:14:16.29,EN,,0,0,0,,The programs don't chop things up in the right way.
Dialogue: 0,0:14:19.45,0:14:22.17,EN,,0,0,0,,Going back to this fundamental principle of computer science
Dialogue: 0,0:14:22.19,0:14:23.63,EN,,0,0,0,,that in order to control something,
Dialogue: 0,0:14:23.63,0:14:24.96,EN,,0,0,0,,you need the name of it,
Dialogue: 0,0:14:25.80,0:14:28.44,EN,,0,0,0,,we don't really have control over thinking about things this way
Dialogue: 0,0:14:28.67,0:14:31.06,EN,,0,0,0,,because we don't have our hands in them explicitly.
Dialogue: 0,0:14:31.06,0:14:33.80,EN,,0,0,0,,We don't have a good language for talking about them.
Dialogue: 0,0:14:35.42,0:14:38.86,EN,,0,0,0,,Well, let's invent an appropriate language
Dialogue: 0,0:14:42.52,0:14:44.04,EN,,0,0,0,,in which we can build these pieces.
Dialogue: 0,0:14:44.78,0:14:47.21,EN,,0,0,0,,The key to the language is these guys,
Dialogue: 0,0:14:47.21,0:14:49.71,EN,,0,0,0,,is what is these things I called signals?
Dialogue: 0,0:14:50.48,0:14:53.32,EN,,0,0,0,,What are these things that are flying on the arrows between the boxes?
Dialogue: 0,0:14:56.88,0:14:57.71,EN,,0,0,0,,Well, those things
Dialogue: 0,0:14:59.85,0:15:03.52,EN,,0,0,0,,are going to be data structures called streams.
Dialogue: 0,0:15:03.79,0:15:05.87,EN,,0,0,0,,That's going to be the key to inventing this language.
Dialogue: 0,0:15:07.98,0:15:08.51,EN,,0,0,0,,What's a stream?
Dialogue: 0,0:15:08.52,0:15:11.50,EN,,0,0,0,,Well, a stream is, like anything else, a data abstraction.
Dialogue: 0,0:15:12.22,0:15:15.82,EN,,0,0,0,,So I should tell you what its selectors and constructors are.
Dialogue: 0,0:15:16.87,0:15:19.48,EN,,0,0,0,,For a stream, we're going to have one constructor
Dialogue: 0,0:15:19.98,0:15:21.43,EN,,0,0,0,,that's called CONS-stream.
Dialogue: 0,0:15:25.69,0:15:28.11,EN,,0,0,0,,CONS-stream is going to put two things together
Dialogue: 0,0:15:28.59,0:15:30.22,EN,,0,0,0,,to form a thing called a stream.
Dialogue: 0,0:15:32.04,0:15:33.85,EN,,0,0,0,,And then to extract things from the stream,
Dialogue: 0,0:15:33.98,0:15:36.11,EN,,0,0,0,,we're going to have a selector called the head of the stream.
Dialogue: 0,0:15:38.01,0:15:38.86,EN,,0,0,0,,So if I have a stream,
Dialogue: 0,0:15:39.00,0:15:40.41,EN,,0,0,0,,I can take its head
Dialogue: 0,0:15:41.13,0:15:42.38,EN,,0,0,0,,or I can take its tail.
Dialogue: 0,0:15:44.72,0:15:47.42,EN,,0,0,0,,And remember, I have to tell you George's contract
Dialogue: 0,0:15:48.24,0:15:52.70,EN,,0,0,0,,to tell you what the axioms are that relate these.
Dialogue: 0,0:15:53.44,0:16:00.17,EN,,0,0,0,,And it's going to be for any x and y,
Dialogue: 0,0:16:03.40,0:16:05.44,EN,,0,0,0,,if I form the CONS-stream and take the head,
Dialogue: 0,0:16:05.69,0:16:11.96,EN,,0,0,0,,the head of CONS-stream of x and y
Dialogue: 0,0:16:13.29,0:16:14.52,EN,,0,0,0,,is going to be x
Dialogue: 0,0:16:16.14,0:16:27.45,EN,,0,0,0,,and the tail of CONS-stream of x and y is going to be y.
Dialogue: 0,0:16:28.44,0:16:34.75,EN,,0,0,0,,So those are the constructor, two selectors for streams, and an axiom.
Dialogue: 0,0:16:34.75,0:16:35.85,EN,,0,0,0,,There's something fishy here.
Dialogue: 0,0:16:36.98,0:16:39.00,EN,,0,0,0,,So you might notice that these are exactly
Dialogue: 0,0:16:40.19,0:16:42.08,EN,,0,0,0,,the axioms for CONS, CAR, and CDR.
Dialogue: 0,0:16:43.63,0:16:46.56,EN,,0,0,0,,So if I said instead of writing CONS-stream I wrote CONS
Dialogue: 0,0:16:47.10,0:16:49.80,EN,,0,0,0,,and I said head was the CAR and tail was the CDR,
Dialogue: 0,0:16:50.76,0:16:52.81,EN,,0,0,0,,those are exactly the axioms for pairs.
Dialogue: 0,0:16:52.81,0:16:54.32,EN,,0,0,0,,And in fact, there's another thing here.
Dialogue: 0,0:16:55.13,0:16:56.80,EN,,0,0,0,,We're going to have a thing called the-empty-stream
Dialogue: 0,0:17:02.80,0:17:04.04,EN,,0,0,0,,which is like the-empty-list.
Dialogue: 0,0:17:08.31,0:17:10.03,EN,,0,0,0,,So why am I introducing this terminology?
Dialogue: 0,0:17:10.03,0:17:12.12,EN,,0,0,0,,Why don't I just keep talking about pairs and lists?
Dialogue: 0,0:17:12.78,0:17:13.79,EN,,0,0,0,,Well, we'll see.
Dialogue: 0,0:17:15.51,0:17:18.24,EN,,0,0,0,,For now, if you like, why don't you just pretend
Dialogue: 0,0:17:18.30,0:17:21.56,EN,,0,0,0,,that streams really are just a terminology for lists.
Dialogue: 0,0:17:21.56,0:17:22.99,EN,,0,0,0,,And we'll see in a little while why
Dialogue: 0,0:17:23.61,0:17:26.09,EN,,0,0,0,,why we want to keep this extra abstraction layer
Dialogue: 0,0:17:26.83,0:17:28.15,EN,,0,0,0,,and not just call them lists.
Dialogue: 0,0:17:32.30,0:17:33.72,EN,,0,0,0,,OK, now that we have streams,
Dialogue: 0,0:17:33.74,0:17:35.85,EN,,0,0,0,,we can start constructing the pieces of the language
Dialogue: 0,0:17:37.04,0:17:38.17,EN,,0,0,0,,to operate on streams.
Dialogue: 0,0:17:38.75,0:17:42.12,EN,,0,0,0,,And there are a whole bunch of very useful things that we could start making.
Dialogue: 0,0:17:42.12,0:17:42.81,EN,,0,0,0,,For instance,
Dialogue: 0,0:17:44.89,0:17:49.79,EN,,0,0,0,,we'll make our map box to take a stream, s,
Dialogue: 0,0:17:54.80,0:17:56.62,EN,,0,0,0,,and a procedure,
Dialogue: 0,0:17:57.80,0:17:59.21,EN,,0,0,0,,and to generate a new stream
Dialogue: 0,0:18:00.14,0:18:02.28,EN,,0,0,0,,which has as its elements
Dialogue: 0,0:18:02.28,0:18:04.88,EN,,0,0,0,,the procedure applied to all the successive elements of s.
Dialogue: 0,0:18:05.87,0:18:07.40,EN,,0,0,0,,In fact, we've seen this before.
Dialogue: 0,0:18:07.40,0:18:10.24,EN,,0,0,0,,This is the procedure map that we did with lists.
Dialogue: 0,0:18:10.95,0:18:12.60,EN,,0,0,0,,And you see it's exactly map,
Dialogue: 0,0:18:12.60,0:18:14.65,EN,,0,0,0,,except we're testing for empty-stream.
Dialogue: 0,0:18:14.65,0:18:15.56,EN,,0,0,0,,Oh, I forgot to mention that.
Dialogue: 0,0:18:15.56,0:18:17.15,EN,,0,0,0,,Empty-stream is like the null test.
Dialogue: 0,0:18:18.03,0:18:20.48,EN,,0,0,0,,So if it's empty, we generate the empty stream.
Dialogue: 0,0:18:20.51,0:18:22.28,EN,,0,0,0,,Otherwise, we form a new stream
Dialogue: 0,0:18:23.52,0:18:27.18,EN,,0,0,0,,whose first element is the procedure applied to the head of the stream,
Dialogue: 0,0:18:28.51,0:18:29.32,EN,,0,0,0,,and whose rest
Dialogue: 0,0:18:29.60,0:18:32.43,EN,,0,0,0,,is gotten by mapping along with the procedure down the tail of the stream.
Dialogue: 0,0:18:33.14,0:18:35.90,EN,,0,0,0,,So that looks exactly like the map procedure we looked at before.
Dialogue: 0,0:18:37.03,0:18:38.20,EN,,0,0,0,,Here's another useful thing.
Dialogue: 0,0:18:38.35,0:18:40.46,EN,,0,0,0,,Filter, this is our filter box.
Dialogue: 0,0:18:40.46,0:18:43.89,EN,,0,0,0,,We're going to have a predicate and a stream.
Dialogue: 0,0:18:43.89,0:18:45.08,EN,,0,0,0,,We're going to make a new stream
Dialogue: 0,0:18:45.80,0:18:48.17,EN,,0,0,0,,consists of all the elements of the original one that satisfy the predicate.
Dialogue: 0,0:18:48.33,0:18:49.48,EN,,0,0,0,,that satisfy the predicate.
Dialogue: 0,0:18:50.38,0:18:51.31,EN,,0,0,0,,That's case analysis.
Dialogue: 0,0:18:51.32,0:18:52.73,EN,,0,0,0,,When there's nothing in the stream,
Dialogue: 0,0:18:53.04,0:18:54.22,EN,,0,0,0,,we return the empty stream.
Dialogue: 0,0:18:56.28,0:18:59.18,EN,,0,0,0,,We test the predicate on the head of the stream.
Dialogue: 0,0:19:00.06,0:19:01.04,EN,,0,0,0,,And if it's true,
Dialogue: 0,0:19:01.53,0:19:02.83,EN,,0,0,0,,we add the head of the stream onto the result
Dialogue: 0,0:19:03.02,0:19:06.22,EN,,0,0,0,,the result of filtering the tail of the stream.
Dialogue: 0,0:19:08.22,0:19:10.04,EN,,0,0,0,,And otherwise, if that predicate was false,
Dialogue: 0,0:19:10.49,0:19:11.98,EN,,0,0,0,,we just filter the tail of the stream.
Dialogue: 0,0:19:13.50,0:19:14.46,EN,,0,0,0,,Right, so there's filter.
Dialogue: 0,0:19:16.59,0:19:18.56,EN,,0,0,0,,Let me run through a couple more rather quickly.
Dialogue: 0,0:19:18.56,0:19:20.70,EN,,0,0,0,,They're all in the book and you can look at them.
Dialogue: 0,0:19:20.88,0:19:21.80,EN,,0,0,0,,Let me just flash through.
Dialogue: 0,0:19:22.11,0:19:22.94,EN,,0,0,0,,Here's accumulate.
Dialogue: 0,0:19:23.26,0:19:26.92,EN,,0,0,0,,Accumulate takes a way of combining things
Dialogue: 0,0:19:27.36,0:19:29.05,EN,,0,0,0,,an initial value in a stream
Dialogue: 0,0:19:29.96,0:19:31.13,EN,,0,0,0,,and sticks them all together.
Dialogue: 0,0:19:31.56,0:19:33.69,EN,,0,0,0,,If the stream's empty, it's just the initial value.
Dialogue: 0,0:19:33.97,0:19:36.20,EN,,0,0,0,,Otherwise, we combine the head of the stream
Dialogue: 0,0:19:36.32,0:19:37.82,EN,,0,0,0,,with the result of accumulating
Dialogue: 0,0:19:38.01,0:19:40.24,EN,,0,0,0,,the tail of the stream starting from the initial value.
Dialogue: 0,0:19:40.90,0:19:42.83,EN,,0,0,0,,So that's what I'd use to add up everything in the stream.
Dialogue: 0,0:19:42.83,0:19:43.98,EN,,0,0,0,,I'd accumulate with plus.
Dialogue: 0,0:19:45.83,0:19:47.56,EN,,0,0,0,,How would I enumerate the leaves of a tree?
Dialogue: 0,0:19:48.06,0:19:52.89,EN,,0,0,0,,Well, if the tree is just a leaf itself,
Dialogue: 0,0:19:53.79,0:19:55.90,EN,,0,0,0,,I make something which only has that node in it.
Dialogue: 0,0:19:56.64,0:19:59.32,EN,,0,0,0,,Otherwise, I append together the stuff of enumerating
Dialogue: 0,0:19:59.61,0:20:02.35,EN,,0,0,0,,the left branch and the right branch.
Dialogue: 0,0:20:04.34,0:20:08.32,EN,,0,0,0,,And then append here is like the ordinary append on lists.
Dialogue: 0,0:20:13.19,0:20:13.85,EN,,0,0,0,,You can look at that.
Dialogue: 0,0:20:13.85,0:20:17.53,EN,,0,0,0,,That's analogous to the ordinary procedure for appending two lists.
Dialogue: 0,0:20:18.91,0:20:20.60,EN,,0,0,0,,Ah... How would I enumerate an interval?
Dialogue: 0,0:20:21.96,0:20:23.77,EN,,0,0,0,,This will take two integers, low and high,
Dialogue: 0,0:20:23.88,0:20:27.00,EN,,0,0,0,,and generate a stream of the integers going from low to high.
Dialogue: 0,0:20:28.32,0:20:29.88,EN,,0,0,0,,And we can make a whole bunch of pieces.
Dialogue: 0,0:20:31.89,0:20:34.48,EN,,0,0,0,,So that's a little language of talking about streams.
Dialogue: 0,0:20:34.49,0:20:35.32,EN,,0,0,0,,Once we have streams,
Dialogue: 0,0:20:35.32,0:20:37.67,EN,,0,0,0,,we can build things for manipulating them.
Dialogue: 0,0:20:37.67,0:20:39.04,EN,,0,0,0,,Again, we're making a language.
Dialogue: 0,0:20:40.20,0:20:42.22,EN,,0,0,0,,And now we can start expressing things in this language.
Dialogue: 0,0:20:43.06,0:20:47.31,EN,,0,0,0,,Here's our original procedure for summing the odd squares in a tree.
Dialogue: 0,0:20:47.31,0:20:52.62,EN,,0,0,0,,And you'll notice it looks exactly now like the block diagram,
Dialogue: 0,0:20:52.64,0:20:54.59,EN,,0,0,0,,like the signal processing block diagram.
Dialogue: 0,0:20:54.59,0:20:57.53,EN,,0,0,0,,So to sum the odd squares in a tree,
Dialogue: 0,0:20:58.06,0:21:00.80,EN,,0,0,0,,we enumerate the leaves of the tree.
Dialogue: 0,0:21:01.32,0:21:03.72,EN,,0,0,0,,We filter that for oddness.
Dialogue: 0,0:21:04.83,0:21:06.54,EN,,0,0,0,,We map that for squareness.
Dialogue: 0,0:21:09.32,0:21:13.34,EN,,0,0,0,,And we accumulate the result of that using addition, starting from 0.
Dialogue: 0,0:21:14.76,0:21:17.20,EN,,0,0,0,,So we can see the pieces that we wanted.
Dialogue: 0,0:21:17.29,0:21:19.36,EN,,0,0,0,,Similarly, the Fibonacci one,
Dialogue: 0,0:21:20.04,0:21:21.88,EN,,0,0,0,,how do we get the odd Fibs?
Dialogue: 0,0:21:22.05,0:21:24.57,EN,,0,0,0,,Well, we enumerate the interval from 1 to n,
Dialogue: 0,0:21:26.32,0:21:28.64,EN,,0,0,0,,we map along that,
Dialogue: 0,0:21:28.99,0:21:30.70,EN,,0,0,0,,computing the Fibonacci of each one.
Dialogue: 0,0:21:30.92,0:21:33.79,EN,,0,0,0,,We filter the result of those for oddness.
Dialogue: 0,0:21:34.81,0:21:36.64,EN,,0,0,0,,And we accumulate all of that stuff
Dialogue: 0,0:21:36.88,0:21:39.12,EN,,0,0,0,,using CONS starting from the empty-list.
Dialogue: 0,0:21:43.65,0:21:47.53,EN,,0,0,0,,OK, what's the advantage of this?
Dialogue: 0,0:21:47.68,0:21:48.59,EN,,0,0,0,,Well, for one thing,
Dialogue: 0,0:21:48.68,0:21:51.15,EN,,0,0,0,,we now have pieces that we can start mixing and matching.
Dialogue: 0,0:21:51.88,0:21:52.64,EN,,0,0,0,,So for instance,
Dialogue: 0,0:21:52.91,0:21:55.08,EN,,0,0,0,,if I wanted to change this, if I wanted to ah...
Dialogue: 0,0:21:58.19,0:22:00.32,EN,,0,0,0,,compute the squares of the integers and then filter them,
Dialogue: 0,0:22:00.33,0:22:01.34,EN,,0,0,0,,all I need to do
Dialogue: 0,0:22:01.90,0:22:03.64,EN,,0,0,0,,is pick up a standard piece like this
Dialogue: 0,0:22:03.68,0:22:05.40,EN,,0,0,0,,it's a map square and put it in.
Dialogue: 0,0:22:06.57,0:22:07.60,EN,,0,0,0,,Or if we wanted to do
Dialogue: 0,0:22:07.69,0:22:11.45,EN,,0,0,0,,this whole Fibonacci computation on the leaves of a tree
Dialogue: 0,0:22:11.58,0:22:12.36,EN,,0,0,0,,rather than a sequence,
Dialogue: 0,0:22:12.38,0:22:13.24,EN,,0,0,0,,all I need to do
Dialogue: 0,0:22:13.40,0:22:15.93,EN,,0,0,0,,is replace this enumerator with that one.
Dialogue: 0,0:22:18.03,0:22:19.82,EN,,0,0,0,,See, the advantage of this stream processing
Dialogue: 0,0:22:20.24,0:22:21.53,EN,,0,0,0,,is that we're establishing--
Dialogue: 0,0:22:22.36,0:22:24.96,EN,,0,0,0,,this is one of the big themes of the course--
Dialogue: 0,0:22:25.29,0:22:27.48,EN,,0,0,0,,we're establishing conventional interfaces
Dialogue: 0,0:22:32.89,0:22:37.15,EN,,0,0,0,,conventional interfaces that allow us to glue things together.
Dialogue: 0,0:22:38.30,0:22:39.55,EN,,0,0,0,,Things like map and filter
Dialogue: 0,0:22:39.79,0:22:41.64,EN,,0,0,0,,are a standard set of components
Dialogue: 0,0:22:41.68,0:22:44.76,EN,,0,0,0,,that we can start using for pasting together programs in all sorts of ways.
Dialogue: 0,0:22:45.75,0:22:48.81,EN,,0,0,0,,It allows us to see the commonality of programs.
Dialogue: 0,0:22:49.95,0:22:50.92,EN,,0,0,0,,I just ought to mention,
Dialogue: 0,0:22:51.08,0:22:53.07,EN,,0,0,0,,I've only showed you two procedures.
Dialogue: 0,0:22:53.86,0:22:55.16,EN,,0,0,0,,But let me emphasize
Dialogue: 0,0:22:55.20,0:22:57.77,EN,,0,0,0,,that this way of putting things together
Dialogue: 0,0:22:57.80,0:23:01.00,EN,,0,0,0,,with maps, filters, and accumulators is very, very general.
Dialogue: 0,0:23:01.41,0:23:07.28,EN,,0,0,0,,It's the generate and test paradigm for programs.
Dialogue: 0,0:23:07.77,0:23:09.10,EN,,0,0,0,,And as an example of that,
Dialogue: 0,0:23:09.39,0:23:12.94,EN,,0,0,0,,Richard Waters, who was at MIT when he was a graduate student,
Dialogue: 0,0:23:12.96,0:23:15.26,EN,,0,0,0,,as part of his thesis research went and analyzed
Dialogue: 0,0:23:15.80,0:23:19.21,EN,,0,0,0,,a large chunk of the IBM scientific subroutine library,
Dialogue: 0,0:23:19.82,0:23:23.31,EN,,0,0,0,,and discovered that about 60% of the programs in it
Dialogue: 0,0:23:24.06,0:23:28.25,EN,,0,0,0,,could be expressed exactly in terms using no more than what we've put here--
Dialogue: 0,0:23:28.86,0:23:30.17,EN,,0,0,0,,map, filter, and accumulate.
Dialogue: 0,0:23:30.57,0:23:31.50,EN,,0,0,0,,All right, let's take a break.
Dialogue: 0,0:23:36.59,0:23:37.12,EN,,0,0,0,,Questions?
Dialogue: 0,0:23:41.18,0:23:42.89,EN,,0,0,0,,AUDIENCE: It seems like the essence of this whole thing
Dialogue: 0,0:23:42.89,0:23:45.96,EN,,0,0,0,,is just that you have a very uniform, simple data structure
Dialogue: 0,0:23:46.25,0:23:47.66,EN,,0,0,0,,to work with, the stream.
Dialogue: 0,0:23:48.38,0:23:48.92,EN,,0,0,0,,PROFESSOR: Right.
Dialogue: 0,0:23:48.92,0:23:50.38,EN,,0,0,0,,The essence is that you, again,
Dialogue: 0,0:23:50.40,0:23:53.07,EN,,0,0,0,,it's this sense of conventional interfaces.
Dialogue: 0,0:23:53.71,0:23:55.61,EN,,0,0,0,,So you can start putting a lot of things together.
Dialogue: 0,0:23:56.01,0:23:58.78,EN,,0,0,0,,And the stream is as you say,
Dialogue: 0,0:23:58.78,0:24:00.89,EN,,0,0,0,,the uniform data structure that supports that.
Dialogue: 0,0:24:00.89,0:24:02.84,EN,,0,0,0,,This is very much like APL, by the way.
Dialogue: 0,0:24:03.60,0:24:05.21,EN,,0,0,0,,APL is very much the same idea,
Dialogue: 0,0:24:05.21,0:24:06.96,EN,,0,0,0,,except in APL, instead of this stream,
Dialogue: 0,0:24:07.13,0:24:08.44,EN,,0,0,0,,you have arrays and vectors.
Dialogue: 0,0:24:09.56,0:24:14.48,EN,,0,0,0,,And a lot of the power of APL is exactly the same reason of the power of this.
Dialogue: 0,0:24:19.91,0:24:20.91,EN,,0,0,0,,OK, thank you.
Dialogue: 0,0:24:20.91,0:24:21.66,EN,,0,0,0,,Let's take a break.
Dialogue: 0,0:24:21.66,0:24:30.35,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING]
Dialogue: 0,0:24:57.47,0:24:57.61,EN,,0,0,0,,All right.
Dialogue: 0,0:24:57.61,0:24:58.59,EN,,0,0,0,,We've been looking at
Dialogue: 0,0:25:00.54,0:25:03.20,EN,,0,0,0,,at ways of organizing computations using streams.
Dialogue: 0,0:25:03.85,0:25:05.47,EN,,0,0,0,,But what I want to do now is just show you two
Dialogue: 0,0:25:05.93,0:25:09.12,EN,,0,0,0,,somewhat more complicated examples of that.
Dialogue: 0,0:25:10.84,0:25:14.12,EN,,0,0,0,,Let's start by thinking about the following
Dialogue: 0,0:25:14.20,0:25:16.81,EN,,0,0,0,,kind of utility procedure that will come in useful.
Dialogue: 0,0:25:16.81,0:25:18.09,EN,,0,0,0,,Suppose I've got a stream.
Dialogue: 0,0:25:19.96,0:25:23.15,EN,,0,0,0,,And the elements of this stream are themselves streams.
Dialogue: 0,0:25:23.98,0:25:26.53,EN,,0,0,0,,So the first thing might be 1, 2, 3.
Dialogue: 0,0:25:32.72,0:25:33.88,EN,,0,0,0,,So I've got a stream.
Dialogue: 0,0:25:33.88,0:25:40.10,EN,,0,0,0,,And each element of the stream is itself a stream.
Dialogue: 0,0:25:40.97,0:25:43.42,EN,,0,0,0,,And what I'd like to do is build a stream
Dialogue: 0,0:25:43.64,0:25:46.75,EN,,0,0,0,,that sort of collects together all of the elements,
Dialogue: 0,0:25:46.76,0:25:49.24,EN,,0,0,0,,pulls all of the elements out of these sub-streams
Dialogue: 0,0:25:50.11,0:25:51.82,EN,,0,0,0,,and strings them all together in one thing.
Dialogue: 0,0:25:52.27,0:25:55.61,EN,,0,0,0,,So just to show you the use of this language, how easy it is,
Dialogue: 0,0:25:56.11,0:25:57.10,EN,,0,0,0,,call that flatten.
Dialogue: 0,0:25:57.95,0:26:10.64,EN,,0,0,0,,And I can define to flatten this stream of streams.
Dialogue: 0,0:26:12.89,0:26:13.80,EN,,0,0,0,,Well, what is that?
Dialogue: 0,0:26:13.96,0:26:16.24,EN,,0,0,0,,That's just an accumulation.
Dialogue: 0,0:26:16.32,0:26:25.05,EN,,0,0,0,,I want to accumulate using append,
Dialogue: 0,0:26:25.07,0:26:26.45,EN,,0,0,0,,by successively appending.
Dialogue: 0,0:26:26.73,0:26:29.29,EN,,0,0,0,,So I accumulate using append streams,
Dialogue: 0,0:26:35.90,0:26:48.20,EN,,0,0,0,,starting with the-empty-stream down that stream of streams.
Dialogue: 0,0:26:54.84,0:26:55.84,EN,,0,0,0,,OK, so there's an example of
Dialogue: 0,0:26:56.92,0:26:59.23,EN,,0,0,0,,how you can start using these higher order things
Dialogue: 0,0:26:59.60,0:27:00.83,EN,,0,0,0,,to do some interesting operations.
Dialogue: 0,0:27:00.83,0:27:05.10,EN,,0,0,0,,In fact, there's another useful thing that I want to do.
Dialogue: 0,0:27:05.10,0:27:07.05,EN,,0,0,0,,I want to define a procedure called flat-map,
Dialogue: 0,0:27:17.18,0:27:20.59,EN,,0,0,0,,flat map of some function and a stream.
Dialogue: 0,0:27:21.84,0:27:25.72,EN,,0,0,0,,And what this is going to do is s will be a stream of elements.
Dialogue: 0,0:27:25.72,0:27:27.69,EN,,0,0,0,,f is going to be a function
Dialogue: 0,0:27:27.72,0:27:30.62,EN,,0,0,0,,for each element in the stream produces another stream.
Dialogue: 0,0:27:31.95,0:27:34.52,EN,,0,0,0,,And what I want to do is take all of the elements and all of those streams
Dialogue: 0,0:27:35.00,0:27:36.00,EN,,0,0,0,,and combine them together.
Dialogue: 0,0:27:36.00,0:27:49.13,EN,,0,0,0,,So that's just going to be the flatten of map f down s.
Dialogue: 0,0:27:51.20,0:27:53.04,EN,,0,0,0,,Each time I apply f to an element of s,
Dialogue: 0,0:27:53.05,0:27:53.85,EN,,0,0,0,,I get a stream.
Dialogue: 0,0:27:54.29,0:27:55.24,EN,,0,0,0,,If I map it all the way down,
Dialogue: 0,0:27:55.24,0:27:56.27,EN,,0,0,0,,I get a stream of streams,
Dialogue: 0,0:27:56.46,0:27:57.42,EN,,0,0,0,,and I'll flatten that.
Dialogue: 0,0:27:58.67,0:28:02.64,EN,,0,0,0,,Well, I want to use that to show you a
Dialogue: 0,0:28:03.87,0:28:05.84,EN,,0,0,0,,a new way to do a familiar kind of problem.
Dialogue: 0,0:28:06.51,0:28:12.27,EN,,0,0,0,,The problem's going to be like a lot of problems you've seen,
Dialogue: 0,0:28:12.28,0:28:13.96,EN,,0,0,0,,although maybe not this particular one.
Dialogue: 0,0:28:14.19,0:28:15.49,EN,,0,0,0,,I'm going to give you an integer, n.
Dialogue: 0,0:28:18.68,0:28:19.93,EN,,0,0,0,,And the problem is going to be
Dialogue: 0,0:28:21.20,0:28:31.53,EN,,0,0,0,,find all pairs and integers i and j,
Dialogue: 0,0:28:32.30,0:28:39.96,EN,,0,0,0,,between 0 and i, with j less than i, up to n,
Dialogue: 0,0:28:42.33,0:28:52.03,EN,,0,0,0,,such that i plus j is prime.
Dialogue: 0,0:28:55.74,0:28:57.92,EN,,0,0,0,,So for example, if n equals 6,
Dialogue: 0,0:28:59.74,0:29:00.78,EN,,0,0,0,,let's make a little table here,
Dialogue: 0,0:29:01.55,0:29:06.67,EN,,0,0,0,,i and j and i plus j.
Dialogue: 0,0:29:09.70,0:29:14.91,EN,,0,0,0,,So for, say, i equals 2 and j equals 1, I'd get 3.
Dialogue: 0,0:29:15.52,0:29:20.38,EN,,0,0,0,,And for i equals 3, I could have j equals 2, and that would be 5.
Dialogue: 0,0:29:21.21,0:29:26.51,EN,,0,0,0,,And 4 and 1 would be 5 and so on,
Dialogue: 0,0:29:26.92,0:29:28.11,EN,,0,0,0,,up until i goes to 6.
Dialogue: 0,0:29:28.40,0:29:32.54,EN,,0,0,0,,And what I'd like to return is to produce a stream
Dialogue: 0,0:29:33.20,0:29:37.04,EN,,0,0,0,,all the triples like this, let's say i, j, and i plus j.
Dialogue: 0,0:29:37.66,0:29:39.55,EN,,0,0,0,,So for each n, I want to generate this stream.
Dialogue: 0,0:29:40.97,0:29:43.68,EN,,0,0,0,,OK, well, that's easy.
Dialogue: 0,0:29:43.68,0:29:44.35,EN,,0,0,0,,Let's build it up.
Dialogue: 0,0:29:47.23,0:29:48.22,EN,,0,0,0,,We start like this.
Dialogue: 0,0:29:50.15,0:29:54.25,EN,,0,0,0,,We're going to say for each i, for each i
Dialogue: 0,0:29:55.24,0:29:56.44,EN,,0,0,0,,we're going to generate a stream.
Dialogue: 0,0:29:57.00,0:29:58.59,EN,,0,0,0,,For each i in the interval 1 through n,
Dialogue: 0,0:29:58.59,0:29:59.76,EN,,0,0,0,,we're going to generate a stream.
Dialogue: 0,0:30:00.66,0:30:01.80,EN,,0,0,0,,What's that stream going to be?
Dialogue: 0,0:30:02.23,0:30:04.04,EN,,0,0,0,,We're going to start by generating all the pairs.
Dialogue: 0,0:30:04.18,0:30:07.55,EN,,0,0,0,,So for each i, we're going to generate,
Dialogue: 0,0:30:08.43,0:30:14.52,EN,,0,0,0,,for each j in the interval 1 to i minus 1,
Dialogue: 0,0:30:16.91,0:30:17.98,EN,,0,0,0,,we'll generate the pair,
Dialogue: 0,0:30:18.35,0:30:20.71,EN,,0,0,0,,or the list with two elements i and j.
Dialogue: 0,0:30:23.78,0:30:27.10,EN,,0,0,0,,So we map along the interval,
Dialogue: 0,0:30:28.60,0:30:29.74,EN,,0,0,0,,generating the pairs.
Dialogue: 0,0:30:31.07,0:30:33.17,EN,,0,0,0,,And for each i, that generates a stream of pairs.
Dialogue: 0,0:30:33.40,0:30:34.49,EN,,0,0,0,,And we flatmap it.
Dialogue: 0,0:30:34.59,0:30:36.20,EN,,0,0,0,,Now we have all the pairs i and j,
Dialogue: 0,0:30:36.81,0:30:38.08,EN,,0,0,0,,such that i is less than j.
Dialogue: 0,0:30:38.73,0:30:39.85,EN,,0,0,0,,So that builds that.
Dialogue: 0,0:30:39.85,0:30:40.76,EN,,0,0,0,,Now we're got to test them.
Dialogue: 0,0:30:42.99,0:30:45.84,EN,,0,0,0,,Well, we take that thing we just built, the flatmap,
Dialogue: 0,0:30:46.94,0:30:51.37,EN,,0,0,0,,and we filter it to see whether the i-- see, we had an i and a j.
Dialogue: 0,0:30:51.66,0:30:54.17,EN,,0,0,0,,i was the first thing in the list,
Dialogue: 0,0:30:54.30,0:30:55.60,EN,,0,0,0,,j was the second thing in the list.
Dialogue: 0,0:30:57.21,0:31:00.01,EN,,0,0,0,,So we have a predicate which says in that list of two elements
Dialogue: 0,0:31:00.22,0:31:02.00,EN,,0,0,0,,is the sum of the CAR and the CDR prime.
Dialogue: 0,0:31:02.07,0:31:05.52,EN,,0,0,0,,And we filter that collection of pairs we just built.
Dialogue: 0,0:31:06.54,0:31:07.85,EN,,0,0,0,,So those are the pairs we want.
Dialogue: 0,0:31:09.42,0:31:10.24,EN,,0,0,0,,Now we go ahead
Dialogue: 0,0:31:10.88,0:31:13.10,EN,,0,0,0,,Now we go ahead and we take the result of that filter
Dialogue: 0,0:31:13.26,0:31:19.05,EN,,0,0,0,,we map along it, generating the list i and j and i plus j.
Dialogue: 0,0:31:19.61,0:31:21.39,EN,,0,0,0,,And that's our procedure prime-sum-pairs.
Dialogue: 0,0:31:22.57,0:31:24.76,EN,,0,0,0,,Ok, and then just to flash it up, here's the whole procedure.
Dialogue: 0,0:31:28.08,0:31:30.97,EN,,0,0,0,,A map, a filter, a flatmap.
Dialogue: 0,0:31:34.85,0:31:35.66,EN,,0,0,0,,There's the whole thing,
Dialogue: 0,0:31:35.66,0:31:37.12,EN,,0,0,0,,even though this isn't particularly readable.
Dialogue: 0,0:31:37.42,0:31:38.94,EN,,0,0,0,,It's just expanding that flatmap.
Dialogue: 0,0:31:39.84,0:31:40.88,EN,,0,0,0,,So there's an example
Dialogue: 0,0:31:43.28,0:31:45.00,EN,,0,0,0,,which illustrates the general point
Dialogue: 0,0:31:45.12,0:31:46.30,EN,,0,0,0,,that nested loops
Dialogue: 0,0:31:47.66,0:31:50.09,EN,,0,0,0,,in this procedure start looking like compositions of
Dialogue: 0,0:31:50.11,0:31:52.81,EN,,0,0,0,,flatmaps of flatmaps of flatmaps of maps and things.
Dialogue: 0,0:31:54.27,0:31:57.61,EN,,0,0,0,,So not only can we enumerate individual things,
Dialogue: 0,0:31:57.61,0:31:58.81,EN,,0,0,0,,but by using flatmaps,
Dialogue: 0,0:31:59.12,0:32:02.24,EN,,0,0,0,,we can do what would correspond to nested loops in most other languages.
Dialogue: 0,0:32:03.23,0:32:03.76,EN,,0,0,0,,Of course,
Dialogue: 0,0:32:04.91,0:32:08.03,EN,,0,0,0,,it's pretty awful to keep writing these flatmaps of flatmaps of flatmaps.
Dialogue: 0,0:32:08.41,0:32:13.00,EN,,0,0,0,,Prime-sum-pairs you saw looked fairly complicated,
Dialogue: 0,0:32:13.56,0:32:15.28,EN,,0,0,0,,even though the individual pieces were easy.
Dialogue: 0,0:32:15.48,0:32:17.13,EN,,0,0,0,,So what you can do, if you like,
Dialogue: 0,0:32:17.15,0:32:20.12,EN,,0,0,0,,is introduced some syntactic sugar that's called collect.
Dialogue: 0,0:32:21.04,0:32:22.68,EN,,0,0,0,,And collect is just an abbreviation
Dialogue: 0,0:32:22.91,0:32:26.16,EN,,0,0,0,,for that nest of flatmaps and filters arranged in that particular way.
Dialogue: 0,0:32:26.16,0:32:28.60,EN,,0,0,0,,Here's prime-sum-pairs again, written using collect.
Dialogue: 0,0:32:29.45,0:32:36.27,EN,,0,0,0,,It says to find all those pairs, I'm going to collect together a result,
Dialogue: 0,0:32:36.52,0:32:39.20,EN,,0,0,0,,which is the list i, j, and i plus j,
Dialogue: 0,0:32:40.84,0:32:45.39,EN,,0,0,0,,that's going to be generated as i runs through the interval from 1 to n
Dialogue: 0,0:32:47.44,0:32:52.32,EN,,0,0,0,,and as j runs through the interval from 1 to i minus 1
Dialogue: 0,0:32:54.16,0:32:56.54,EN,,0,0,0,,such that i plus j is prime.
Dialogue: 0,0:32:58.04,0:33:00.32,EN,,0,0,0,,So I'm not going to say what collect does in general.
Dialogue: 0,0:33:00.69,0:33:02.75,EN,,0,0,0,,You can look at that by looking at it in the book.
Dialogue: 0,0:33:03.42,0:33:05.45,EN,,0,0,0,,But pretty much, you can see that the pieces of this
Dialogue: 0,0:33:05.84,0:33:08.60,EN,,0,0,0,,are the pieces of that original procedure I wrote.
Dialogue: 0,0:33:08.82,0:33:11.40,EN,,0,0,0,,And this collect is just some syntactic sugar
Dialogue: 0,0:33:11.44,0:33:14.80,EN,,0,0,0,,for automatically generating that nest of flatmaps and flatmaps.
Dialogue: 0,0:33:16.31,0:33:20.33,EN,,0,0,0,,OK, well, let me do one more example
Dialogue: 0,0:33:20.67,0:33:22.00,EN,,0,0,0,,that shows you the same kind of thing.
Dialogue: 0,0:33:22.12,0:33:23.53,EN,,0,0,0,,Here's a very famous problem
Dialogue: 0,0:33:24.70,0:33:28.75,EN,,0,0,0,,that's used to illustrate a lot of so-called backtracking computer algorithms
Dialogue: 0,0:33:28.76,0:33:30.20,EN,,0,0,0,,This is the eight queens problem.
Dialogue: 0,0:33:30.20,0:33:31.08,EN,,0,0,0,,This is a chess board.
Dialogue: 0,0:33:32.37,0:33:33.64,EN,,0,0,0,,And the eight queens problem says,
Dialogue: 0,0:33:33.64,0:33:35.85,EN,,0,0,0,,find a way to put down eight queens on a chess board
Dialogue: 0,0:33:36.44,0:33:38.00,EN,,0,0,0,,so that no two are attacking each other.
Dialogue: 0,0:33:38.00,0:33:40.60,EN,,0,0,0,,And here's a particular solution to the eight queens problem.
Dialogue: 0,0:33:41.21,0:33:43.68,EN,,0,0,0,,So I have to make sure to put down queens
Dialogue: 0,0:33:43.71,0:33:46.80,EN,,0,0,0,,no two are in the same row or the same column
Dialogue: 0,0:33:47.72,0:33:49.47,EN,,0,0,0,,or sit along the same diagonal.
Dialogue: 0,0:33:51.41,0:33:56.40,EN,,0,0,0,,Now, there's sort of a standard way of doing that.
Dialogue: 0,0:33:59.74,0:34:01.48,EN,,0,0,0,,Well, first we need to do is
Dialogue: 0,0:34:02.54,0:34:04.62,EN,,0,0,0,,below the surface, at George's level.
Dialogue: 0,0:34:04.94,0:34:08.09,EN,,0,0,0,,We have to find some way to represent a board, and represent positions.
Dialogue: 0,0:34:08.09,0:34:09.52,EN,,0,0,0,,And we'll not worry about that.
Dialogue: 0,0:34:09.80,0:34:12.78,EN,,0,0,0,,But let's assume that there's a predicate called safe.
Dialogue: 0,0:34:16.14,0:34:17.55,EN,,0,0,0,,And what safe is going to do
Dialogue: 0,0:34:17.96,0:34:20.84,EN,,0,0,0,,is going to say given that I have a bunch of queens down on the chess board,
Dialogue: 0,0:34:21.36,0:34:24.54,EN,,0,0,0,,is it OK to put a queen in this particular spot?
Dialogue: 0,0:34:25.40,0:34:31.26,EN,,0,0,0,,So safe is going to take a row and a column.
Dialogue: 0,0:34:32.76,0:34:35.47,EN,,0,0,0,,That's going to be a place where I'm going to try and put down the next queen,
Dialogue: 0,0:34:36.06,0:34:42.76,EN,,0,0,0,,and the rest of positions.
Dialogue: 0,0:34:45.58,0:34:46.75,EN,,0,0,0,,And what safe will say
Dialogue: 0,0:34:46.86,0:34:51.68,EN,,0,0,0,,is given that I already have queens down in these positions,
Dialogue: 0,0:34:53.02,0:34:54.76,EN,,0,0,0,,is it safe to put another queen down
Dialogue: 0,0:34:55.10,0:34:57.20,EN,,0,0,0,,in that row and that column?
Dialogue: 0,0:34:58.30,0:34:59.36,EN,,0,0,0,,And let's not worry about that.
Dialogue: 0,0:34:59.36,0:35:01.38,EN,,0,0,0,,That's George's problem. and it's not hard to write.
Dialogue: 0,0:35:01.38,0:35:06.27,EN,,0,0,0,,You just have to check whether this thing contains any things
Dialogue: 0,0:35:06.30,0:35:08.52,EN,,0,0,0,,on that row or that column or in that diagonal.
Dialogue: 0,0:35:10.53,0:35:13.12,EN,,0,0,0,,Now, how would you organize the program given that?
Dialogue: 0,0:35:13.84,0:35:17.21,EN,,0,0,0,,And there's sort of a traditional way to organize it
Dialogue: 0,0:35:17.93,0:35:18.97,EN,,0,0,0,,called backtracking.
Dialogue: 0,0:35:20.52,0:35:23.21,EN,,0,0,0,,And it says, well, let's start off
Dialogue: 0,0:35:25.13,0:35:28.88,EN,,0,0,0,,let's think about all the ways of putting the first queen down
Dialogue: 0,0:35:30.04,0:35:31.34,EN,,0,0,0,,in the first column.
Dialogue: 0,0:35:31.45,0:35:32.24,EN,,0,0,0,,There are eight ways.
Dialogue: 0,0:35:32.58,0:35:35.00,EN,,0,0,0,,Well, let's say try the first column.
Dialogue: 0,0:35:35.88,0:35:37.30,EN,,0,0,0,,Try column 1, row 1.
Dialogue: 0,0:35:37.30,0:35:38.70,EN,,0,0,0,,These branches are going to represent
Dialogue: 0,0:35:40.17,0:35:41.88,EN,,0,0,0,,the possibilities at each level.
Dialogue: 0,0:35:43.36,0:35:45.53,EN,,0,0,0,,So I'll try and put a queen down in the first column.
Dialogue: 0,0:35:46.14,0:35:47.74,EN,,0,0,0,,And now given that it's in the first column,
Dialogue: 0,0:35:47.77,0:35:49.98,EN,,0,0,0,,I'll try and put the next queen down in the first column.
Dialogue: 0,0:35:50.60,0:35:52.17,EN,,0,0,0,,That's no good, they're both...
Dialogue: 0,0:35:53.31,0:35:54.60,EN,,0,0,0,,I'll try and put the first queen,
Dialogue: 0,0:35:54.86,0:35:56.80,EN,,0,0,0,,the one in the first column, down in the first row.
Dialogue: 0,0:35:56.92,0:35:57.47,EN,,0,0,0,,I'm sorry.
Dialogue: 0,0:35:59.05,0:36:01.39,EN,,0,0,0,,And then given that, we'll put the next queen down in the first row.
Dialogue: 0,0:36:01.39,0:36:02.09,EN,,0,0,0,,And that's no good.
Dialogue: 0,0:36:02.09,0:36:03.18,EN,,0,0,0,,So I'll back up to here.
Dialogue: 0,0:36:04.20,0:36:04.72,EN,,0,0,0,,And I'll say,
Dialogue: 0,0:36:04.83,0:36:06.86,EN,,0,0,0,,oh, can I put the first queen down in the second row?
Dialogue: 0,0:36:07.32,0:36:08.38,EN,,0,0,0,,Well, that's no good.
Dialogue: 0,0:36:08.55,0:36:09.76,EN,,0,0,0,,Oh, can I put it down in the third row?
Dialogue: 0,0:36:09.76,0:36:10.52,EN,,0,0,0,,Well, that's good.
Dialogue: 0,0:36:12.79,0:36:15.13,EN,,0,0,0,,Well, now can I put the next queen down in the first column?
Dialogue: 0,0:36:15.38,0:36:17.82,EN,,0,0,0,,Well, I can't visualize this chess board anymore,
Dialogue: 0,0:36:17.82,0:36:18.86,EN,,0,0,0,,but I think that's right.
Dialogue: 0,0:36:19.19,0:36:20.45,EN,,0,0,0,,And I try the next one.
Dialogue: 0,0:36:20.45,0:36:24.17,EN,,0,0,0,,And at each place, I go as far down this tree as I can.
Dialogue: 0,0:36:24.54,0:36:25.64,EN,,0,0,0,,And I back up.
Dialogue: 0,0:36:25.64,0:36:28.97,EN,,0,0,0,,If I get down to here and find no possibilities below there,
Dialogue: 0,0:36:29.00,0:36:30.12,EN,,0,0,0,,I back all the way up to here,
Dialogue: 0,0:36:30.28,0:36:32.44,EN,,0,0,0,,and now start again generating this sub-tree.
Dialogue: 0,0:36:33.26,0:36:34.32,EN,,0,0,0,,And I sort of walk around.
Dialogue: 0,0:36:35.05,0:36:37.26,EN,,0,0,0,,And finally, if I ever manage to get all the way down,
Dialogue: 0,0:36:37.72,0:36:38.59,EN,,0,0,0,,I've found a solution.
Dialogue: 0,0:36:39.82,0:36:41.98,EN,,0,0,0,,So that's a typical sort of
Dialogue: 0,0:36:43.12,0:36:45.93,EN,,0,0,0,,paradigm that's used a lot in AI programming.
Dialogue: 0,0:36:45.93,0:36:47.30,EN,,0,0,0,,It's called backtracking search.
Dialogue: 0,0:36:57.47,0:37:03.04,EN,,0,0,0,,And it's really unnecessary.
Dialogue: 0,0:37:03.86,0:37:06.55,EN,,0,0,0,,You saw me get confused when I was visualizing this thing.
Dialogue: 0,0:37:06.81,0:37:08.25,EN,,0,0,0,,And you sort of see the complication.
Dialogue: 0,0:37:08.55,0:37:10.76,EN,,0,0,0,,This is a complicated thing to say.
Dialogue: 0,0:37:10.76,0:37:11.82,EN,,0,0,0,,Why is it complicated?
Dialogue: 0,0:37:12.39,0:37:13.29,EN,,0,0,0,,Its because somehow
Dialogue: 0,0:37:13.53,0:37:17.39,EN,,0,0,0,,this program is too inordinately concerned with time.
Dialogue: 0,0:37:18.58,0:37:20.43,EN,,0,0,0,,It's too much-- I try this one, and I try this one,
Dialogue: 0,0:37:20.49,0:37:22.38,EN,,0,0,0,,and I go back to the last possibility.
Dialogue: 0,0:37:22.89,0:37:24.34,EN,,0,0,0,,And that's a complicated thing.
Dialogue: 0,0:37:24.34,0:37:26.36,EN,,0,0,0,,If I stop worrying about time so much,
Dialogue: 0,0:37:28.04,0:37:29.76,EN,,0,0,0,,then there's a much simpler way to describe this.
Dialogue: 0,0:37:31.20,0:37:32.36,EN,,0,0,0,,It says, let's imagine
Dialogue: 0,0:37:33.31,0:37:36.57,EN,,0,0,0,,that I have in my hands
Dialogue: 0,0:37:38.32,0:37:42.16,EN,,0,0,0,,the tree down to k minus 1 levels.
Dialogue: 0,0:37:43.40,0:37:46.32,EN,,0,0,0,,See, suppose I had in my hands all possible ways
Dialogue: 0,0:37:48.09,0:37:52.19,EN,,0,0,0,,to solve... to put down queens in the first k columns.
Dialogue: 0,0:37:53.56,0:37:54.61,EN,,0,0,0,,Suppose I just had that.
Dialogue: 0,0:37:54.61,0:37:55.79,EN,,0,0,0,,Let's not worry about how we get it.
Dialogue: 0,0:37:57.07,0:37:59.20,EN,,0,0,0,,Well, then, how do I extend that?
Dialogue: 0,0:37:59.20,0:38:02.16,EN,,0,0,0,,How do I find all possible ways to put down queens in the next column?
Dialogue: 0,0:38:02.48,0:38:03.13,EN,,0,0,0,,It's really easy.
Dialogue: 0,0:38:03.62,0:38:06.41,EN,,0,0,0,,For each of these positions I have,
Dialogue: 0,0:38:07.82,0:38:13.96,EN,,0,0,0,,I enjoin, I think about putting down a queen in each row
Dialogue: 0,0:38:15.08,0:38:16.16,EN,,0,0,0,,to make the next thing.
Dialogue: 0,0:38:16.16,0:38:17.29,EN,,0,0,0,,And then for each one I put down,
Dialogue: 0,0:38:17.44,0:38:19.71,EN,,0,0,0,,I filter those by the ones that are safe.
Dialogue: 0,0:38:21.80,0:38:22.99,EN,,0,0,0,,So instead of thinking about
Dialogue: 0,0:38:22.99,0:38:24.67,EN,,0,0,0,,this tree as generated step by step,
Dialogue: 0,0:38:24.94,0:38:26.86,EN,,0,0,0,,I say, suppose I had it all there.
Dialogue: 0,0:38:29.68,0:38:32.41,EN,,0,0,0,,And to extend it from level k minus 1 to level k,
Dialogue: 0,0:38:32.64,0:38:36.24,EN,,0,0,0,,I just need to extend each thing in all possible ways
Dialogue: 0,0:38:36.48,0:38:37.80,EN,,0,0,0,,and only keep the ones that are safe.
Dialogue: 0,0:38:37.80,0:38:39.23,EN,,0,0,0,,And that will give me the tree to level k.
Dialogue: 0,0:38:39.30,0:38:40.67,EN,,0,0,0,,And that's a recursive strategy
Dialogue: 0,0:38:40.89,0:38:42.17,EN,,0,0,0,,for solving the eight queens problem.
Dialogue: 0,0:38:44.53,0:38:45.34,EN,,0,0,0,,All right, well, let's look at it.
Dialogue: 0,0:38:50.33,0:38:52.68,EN,,0,0,0,,To solve the eight queens problem
Dialogue: 0,0:38:53.00,0:38:55.53,EN,,0,0,0,,on a board of some specified size,
Dialogue: 0,0:38:58.92,0:39:01.03,EN,,0,0,0,,we write a sub-procedure called fill-columns.
Dialogue: 0,0:39:01.13,0:39:04.86,EN,,0,0,0,,Fill-columns is going to put down queens up through column k.
Dialogue: 0,0:39:06.35,0:39:07.70,EN,,0,0,0,,And here's the pattern of the recursion.
Dialogue: 0,0:39:07.70,0:39:10.92,EN,,0,0,0,,I'm going to call fill-columns with the size eventually.
Dialogue: 0,0:39:12.99,0:39:15.28,EN,,0,0,0,,So fill-columns says how to put down queens safely
Dialogue: 0,0:39:15.29,0:39:17.16,EN,,0,0,0,,safely in the first k columns of this chess board
Dialogue: 0,0:39:17.20,0:39:19.58,EN,,0,0,0,,with a size number of rows in it.
Dialogue: 0,0:39:20.36,0:39:21.64,EN,,0,0,0,,If k is equal to 0,
Dialogue: 0,0:39:22.27,0:39:23.60,EN,,0,0,0,,well, then I don't have to put anything down.
Dialogue: 0,0:39:23.94,0:39:25.93,EN,,0,0,0,,So my solution is just an empty chess board.
Dialogue: 0,0:39:26.71,0:39:28.07,EN,,0,0,0,,Otherwise, I'm going to do some stuff.
Dialogue: 0,0:39:28.35,0:39:29.44,EN,,0,0,0,,And I'm going to use collect.
Dialogue: 0,0:39:30.81,0:39:31.77,EN,,0,0,0,,And here's the collect.
Dialogue: 0,0:39:34.33,0:39:41.91,EN,,0,0,0,,I find all ways to put down queens in the first k minus 1 columns.
Dialogue: 0,0:39:42.19,0:39:43.32,EN,,0,0,0,,And this was just what I set for.
Dialogue: 0,0:39:43.32,0:39:46.36,EN,,0,0,0,,Imagine I have this tree down to k minus 1 levels.
Dialogue: 0,0:39:48.88,0:39:52.11,EN,,0,0,0,,And then I find all ways of trying a row,
Dialogue: 0,0:39:52.52,0:39:54.13,EN,,0,0,0,,that's just each of the possible rows.
Dialogue: 0,0:39:54.13,0:39:55.04,EN,,0,0,0,,They're size rows,
Dialogue: 0,0:39:55.31,0:39:56.49,EN,,0,0,0,,so that's enumerate interval.
Dialogue: 0,0:39:58.04,0:39:59.79,EN,,0,0,0,,And now what I do is I collect together
Dialogue: 0,0:40:03.15,0:40:05.82,EN,,0,0,0,,the new row I'm going to try and column k
Dialogue: 0,0:40:07.95,0:40:08.95,EN,,0,0,0,,with the rest of the queens.
Dialogue: 0,0:40:08.95,0:40:10.09,EN,,0,0,0,,I adjoin a position.
Dialogue: 0,0:40:10.20,0:40:11.29,EN,,0,0,0,,This is George's problem.
Dialogue: 0,0:40:11.29,0:40:12.75,EN,,0,0,0,,An adjoined position is like safe.
Dialogue: 0,0:40:13.64,0:40:15.28,EN,,0,0,0,,It's a thing that takes a row
Dialogue: 0,0:40:15.50,0:40:17.04,EN,,0,0,0,,and a column and the rest of the positions
Dialogue: 0,0:40:17.07,0:40:19.02,EN,,0,0,0,,and makes a new position collection.
Dialogue: 0,0:40:19.66,0:40:25.77,EN,,0,0,0,,So I adjoin a position of a new row and a new column
Dialogue: 0,0:40:26.06,0:40:27.68,EN,,0,0,0,,to the rest of the queens,
Dialogue: 0,0:40:28.57,0:40:29.76,EN,,0,0,0,,where the rest of the queens
Dialogue: 0,0:40:29.92,0:40:31.45,EN,,0,0,0,,runs through all possible ways
Dialogue: 0,0:40:31.87,0:40:34.16,EN,,0,0,0,,of solving the problem in k minus 1 columns.
Dialogue: 0,0:40:34.62,0:40:37.04,EN,,0,0,0,,And the new row runs through all possible rows
Dialogue: 0,0:40:37.85,0:40:40.76,EN,,0,0,0,,such that it was safe to put one there.
Dialogue: 0,0:40:43.24,0:40:44.70,EN,,0,0,0,,And that's the whole program.
Dialogue: 0,0:40:46.33,0:40:47.31,EN,,0,0,0,,There's the whole procedure.
Dialogue: 0,0:40:49.84,0:40:52.43,EN,,0,0,0,,Not only that, that doesn't just solve the eight queens problem,
Dialogue: 0,0:40:53.42,0:40:56.68,EN,,0,0,0,,Right? It gives you all solutions to the eight queens problem.
Dialogue: 0,0:40:56.68,0:40:58.48,EN,,0,0,0,,When you're done, you have a stream.
Dialogue: 0,0:40:58.48,0:41:01.90,EN,,0,0,0,,And the elements of that stream are all possible ways of solving that problem.
Dialogue: 0,0:41:05.31,0:41:06.26,EN,,0,0,0,,Why is that simpler?
Dialogue: 0,0:41:06.26,0:41:08.54,EN,,0,0,0,,Well, we threw away the whole idea that
Dialogue: 0,0:41:08.88,0:41:11.52,EN,,0,0,0,,is some process that happens in time with state.
Dialogue: 0,0:41:12.72,0:41:14.42,EN,,0,0,0,,And we just said it's a whole collection of stuff.
Dialogue: 0,0:41:14.94,0:41:16.00,EN,,0,0,0,,And that's why it's simpler.
Dialogue: 0,0:41:18.00,0:41:20.11,EN,,0,0,0,,Right? We've changed our view.
Dialogue: 0,0:41:20.11,0:41:22.59,EN,,0,0,0,,Remember, that's where we started today.
Dialogue: 0,0:41:22.82,0:41:26.23,EN,,0,0,0,,We've changed our view of what it is we're trying to model.
Dialogue: 0,0:41:26.23,0:41:29.20,EN,,0,0,0,,we stop modeling things that evolve in time
Dialogue: 0,0:41:29.37,0:41:31.31,EN,,0,0,0,,have steps and have state.
Dialogue: 0,0:41:31.75,0:41:33.79,EN,,0,0,0,,And instead, we're trying to model this global thing
Dialogue: 0,0:41:33.80,0:41:35.93,EN,,0,0,0,,like the whole flight of the chalk,
Dialogue: 0,0:41:36.28,0:41:38.88,EN,,0,0,0,,rather than its state at each instant.
Dialogue: 0,0:41:40.75,0:41:41.44,EN,,0,0,0,,Any questions?
Dialogue: 0,0:41:44.08,0:41:46.20,EN,,0,0,0,,AUDIENCE: It looks to me like backtracking would be
Dialogue: 0,0:41:46.22,0:41:48.96,EN,,0,0,0,,searching for the first solution it can find,
Dialogue: 0,0:41:49.31,0:41:51.48,EN,,0,0,0,,whereas this recursive search
Dialogue: 0,0:41:51.48,0:41:53.26,EN,,0,0,0,,would be looking for all solutions.
Dialogue: 0,0:41:53.32,0:41:53.60,EN,,0,0,0,,PROFESSOR: Right.
Dialogue: 0,0:41:54.03,0:41:55.26,EN,,0,0,0,,AUDIENCE: And it seems that
Dialogue: 0,0:41:55.26,0:41:57.92,EN,,0,0,0,,if you have a large enough area to search,
Dialogue: 0,0:41:57.92,0:42:00.92,EN,,0,0,0,,that the second is going to become impossible.
Dialogue: 0,0:42:01.36,0:42:05.93,EN,,0,0,0,,PROFESSOR: OK, the answer to that question
Dialogue: 0,0:42:07.13,0:42:08.44,EN,,0,0,0,,is the whole rest of this lecture.
Dialogue: 0,0:42:08.57,0:42:10.54,EN,,0,0,0,,It's exactly the right question.
Dialogue: 0,0:42:13.87,0:42:15.74,EN,,0,0,0,,And without trying to anticipate the lecture too much,
Dialogue: 0,0:42:15.96,0:42:19.23,EN,,0,0,0,,you should start being suspicious at this point,
Dialogue: 0,0:42:19.84,0:42:21.84,EN,,0,0,0,,and exactly those kinds of suspicions. Isn't it?
Dialogue: 0,0:42:22.22,0:42:24.51,EN,,0,0,0,,It's wonderful, but isn't it so terribly inefficient?
Dialogue: 0,0:42:24.83,0:42:26.03,EN,,0,0,0,,That's where we're going.
Dialogue: 0,0:42:28.10,0:42:30.02,EN,,0,0,0,,So I won't answer now, but I'll answer later.
Dialogue: 0,0:42:33.35,0:42:34.60,EN,,0,0,0,,OK, let's take a break.
Dialogue: 0,0:42:34.60,0:42:44.51,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING]
Dialogue: 0,0:43:29.65,0:43:33.76,EN,,0,0,0,,Well, by now you should be starting to get suspicious.
Dialogue: 0,0:43:35.60,0:43:39.26,EN,,0,0,0,,See, I've showed your this simple, elegant
Dialogue: 0,0:43:40.51,0:43:42.28,EN,,0,0,0,,of putting programs together,
Dialogue: 0,0:43:42.86,0:43:46.91,EN,,0,0,0,,very unlike these other traditional programs
Dialogue: 0,0:43:46.92,0:43:48.19,EN,,0,0,0,,that sum the odd squares
Dialogue: 0,0:43:48.72,0:43:51.32,EN,,0,0,0,,or compute the odd Fibonacci numbers.
Dialogue: 0,0:43:53.74,0:43:55.48,EN,,0,0,0,,Very unlike these programs that mix up
Dialogue: 0,0:43:55.85,0:43:58.84,EN,,0,0,0,,the enumerator and the filter and the accumulator.
Dialogue: 0,0:44:00.44,0:44:01.82,EN,,0,0,0,,And by mixing it up,
Dialogue: 0,0:44:02.20,0:44:04.59,EN,,0,0,0,,we don't have all of these wonderful
Dialogue: 0,0:44:04.62,0:44:07.34,EN,,0,0,0,,conceptual advantages of these streams pieces,
Dialogue: 0,0:44:07.82,0:44:09.53,EN,,0,0,0,,these wonderful mix and match components
Dialogue: 0,0:44:09.55,0:44:11.77,EN,,0,0,0,,for putting together lots and lots of programs.
Dialogue: 0,0:44:13.80,0:44:14.25,EN,,0,0,0,,On the other hand,
Dialogue: 0,0:44:14.28,0:44:16.88,EN,,0,0,0,,most of the programs you've seen look like these ugly ones.
Dialogue: 0,0:44:18.34,0:44:18.94,EN,,0,0,0,,Why's that?
Dialogue: 0,0:44:19.20,0:44:20.59,EN,,0,0,0,,Can it possibly be
Dialogue: 0,0:44:21.16,0:44:24.30,EN,,0,0,0,,that computer scientists are so obtuse
Dialogue: 0,0:44:25.42,0:44:26.44,EN,,0,0,0,,that they don't notice
Dialogue: 0,0:44:27.07,0:44:28.75,EN,,0,0,0,,that if you'd merely did this thing,
Dialogue: 0,0:44:29.63,0:44:31.93,EN,,0,0,0,,then you can get this great programming elegance?
Dialogue: 0,0:44:33.62,0:44:34.78,EN,,0,0,0,,There's got to be a catch.
Dialogue: 0,0:44:36.76,0:44:39.05,EN,,0,0,0,,And it's actually pretty easy to see what the catch is.
Dialogue: 0,0:44:39.51,0:44:41.74,EN,,0,0,0,,Let's think about the following problem.
Dialogue: 0,0:44:42.03,0:44:45.47,EN,,0,0,0,,Suppose I tell you to find the second prime
Dialogue: 0,0:44:46.16,0:44:48.16,EN,,0,0,0,,between 10,000 and 1 million,
Dialogue: 0,0:44:49.12,0:44:50.56,EN,,0,0,0,,or if your computer's larger,
Dialogue: 0,0:44:50.59,0:44:53.05,EN,,0,0,0,,say between 10,000 and 100 billion, or something.
Dialogue: 0,0:44:54.32,0:44:55.45,EN,,0,0,0,,And you say, oh, that's easy.
Dialogue: 0,0:44:55.47,0:44:56.65,EN,,0,0,0,,I can do that with a stream.
Dialogue: 0,0:44:57.08,0:44:59.87,EN,,0,0,0,,All I do is I enumerate
Dialogue: 0,0:45:00.57,0:45:02.89,EN,,0,0,0,,the interval from 10,000 to 1 million.
Dialogue: 0,0:45:04.16,0:45:06.51,EN,,0,0,0,,So I get all those integers from 10,000 to 1 million.
Dialogue: 0,0:45:06.80,0:45:08.64,EN,,0,0,0,,I filter them for prime-ness,
Dialogue: 0,0:45:09.39,0:45:11.10,EN,,0,0,0,,so test all of them and see if they're prime.
Dialogue: 0,0:45:11.76,0:45:12.83,EN,,0,0,0,,And I take the second element.
Dialogue: 0,0:45:12.84,0:45:14.04,EN,,0,0,0,,Right? That's the head of the tail.
Dialogue: 0,0:45:15.79,0:45:17.38,EN,,0,0,0,,OK? Well, that's clearly pretty ridiculous.
Dialogue: 0,0:45:21.66,0:45:23.20,EN,,0,0,0,,We'd not even have room in the machine
Dialogue: 0,0:45:23.58,0:45:25.24,EN,,0,0,0,,Right? To store the integers in the first place,
Dialogue: 0,0:45:25.28,0:45:26.35,EN,,0,0,0,,much less to test them.
Dialogue: 0,0:45:27.04,0:45:28.64,EN,,0,0,0,,And then I only want the second one.
Dialogue: 0,0:45:29.81,0:45:34.94,EN,,0,0,0,,See, the power of this traditional programming style
Dialogue: 0,0:45:36.43,0:45:37.68,EN,,0,0,0,,is exactly its weakness,
Dialogue: 0,0:45:37.96,0:45:38.94,EN,,0,0,0,,that we're mixing up
Dialogue: 0,0:45:39.61,0:45:43.50,EN,,0,0,0,,the enumerating and the testing and the accumulating.
Dialogue: 0,0:45:44.88,0:45:46.46,EN,,0,0,0,,Right? We sort of don't do it all.
Dialogue: 0,0:45:46.67,0:45:49.18,EN,,0,0,0,,So by the actual... so the very thing
Dialogue: 0,0:45:49.45,0:45:51.74,EN,,0,0,0,,makes it conceptually ugly
Dialogue: 0,0:45:52.20,0:45:53.80,EN,,0,0,0,,is the very thing that makes it efficient.
Dialogue: 0,0:45:54.91,0:45:55.84,EN,,0,0,0,,Right? It's this mixing up.
Dialogue: 0,0:45:57.80,0:45:59.34,EN,,0,0,0,,So it seems that all I've done this morning so far
Dialogue: 0,0:45:59.34,0:46:00.42,EN,,0,0,0,,is just confuse you.
Dialogue: 0,0:46:00.42,0:46:03.10,EN,,0,0,0,,I showed you this wonderful way that programming might work,
Dialogue: 0,0:46:03.10,0:46:03.96,EN,,0,0,0,,except that it doesn't.
Dialogue: 0,0:46:05.84,0:46:08.32,EN,,0,0,0,,Well, here's where the wonderful thing happens.
Dialogue: 0,0:46:09.04,0:46:10.57,EN,,0,0,0,,It turns out in this game
Dialogue: 0,0:46:11.21,0:46:13.84,EN,,0,0,0,,that we really can have our cake and eat it too.
Dialogue: 0,0:46:14.87,0:46:16.11,EN,,0,0,0,,And what I mean by that
Dialogue: 0,0:46:18.09,0:46:21.15,EN,,0,0,0,,is that we really can write stream programs
Dialogue: 0,0:46:21.16,0:46:22.48,EN,,0,0,0,,exactly like the ones I wrote
Dialogue: 0,0:46:23.55,0:46:27.74,EN,,0,0,0,,and arrange things so that when the machine actually runs,
Dialogue: 0,0:46:28.33,0:46:31.52,EN,,0,0,0,,it's as efficient as running this traditional programming style
Dialogue: 0,0:46:31.71,0:46:34.28,EN,,0,0,0,,that mixes up the generation and the test.
Dialogue: 0,0:46:36.16,0:46:38.80,EN,,0,0,0,,Well, that sounds pretty magic.
Dialogue: 0,0:46:40.77,0:46:41.82,EN,,0,0,0,,The key to this
Dialogue: 0,0:46:42.00,0:46:43.69,EN,,0,0,0,,is that streams are not lists.
Dialogue: 0,0:46:48.09,0:46:49.79,EN,,0,0,0,,We'll see this carefully in a second, but for now,
Dialogue: 0,0:46:49.80,0:46:51.77,EN,,0,0,0,,let's take a look at that slide again.
Dialogue: 0,0:46:52.24,0:46:53.80,EN,,0,0,0,,The image you should have here
Dialogue: 0,0:46:53.84,0:46:55.58,EN,,0,0,0,,of this signal processing system
Dialogue: 0,0:46:57.26,0:46:58.72,EN,,0,0,0,,is that what's going to happen
Dialogue: 0,0:46:59.13,0:47:00.92,EN,,0,0,0,,is there's sort of this box
Dialogue: 0,0:47:01.18,0:47:03.58,EN,,0,0,0,,that has the integers sitting in it.
Dialogue: 0,0:47:05.36,0:47:06.40,EN,,0,0,0,,And there's this filter
Dialogue: 0,0:47:07.45,0:47:09.37,EN,,0,0,0,,that's connected to it and it's tugging on them.
Dialogue: 0,0:47:10.94,0:47:13.15,EN,,0,0,0,,And then there's someone who's tugging on this stuff
Dialogue: 0,0:47:13.31,0:47:14.91,EN,,0,0,0,,saying what comes out of the filter.
Dialogue: 0,0:47:16.79,0:47:18.70,EN,,0,0,0,,And the image you should have is that
Dialogue: 0,0:47:18.99,0:47:20.72,EN,,0,0,0,,someone says, well, what's the first prime,
Dialogue: 0,0:47:22.67,0:47:24.14,EN,,0,0,0,,and tugs on this filter.
Dialogue: 0,0:47:24.59,0:47:26.12,EN,,0,0,0,,And the filter tugs on the integers.
Dialogue: 0,0:47:28.02,0:47:29.15,EN,,0,0,0,,And you look only at that much,
Dialogue: 0,0:47:29.16,0:47:30.93,EN,,0,0,0,,and then say, oh, I really wanted the second one.
Dialogue: 0,0:47:30.93,0:47:31.95,EN,,0,0,0,,What's the second prime?
Dialogue: 0,0:47:33.71,0:47:35.37,EN,,0,0,0,,And that no other computation
Dialogue: 0,0:47:35.37,0:47:36.64,EN,,0,0,0,,no computation gets done
Dialogue: 0,0:47:36.64,0:47:38.32,EN,,0,0,0,,except when you tug on these things.
Dialogue: 0,0:47:40.50,0:47:41.41,EN,,0,0,0,,Let me try that again.
Dialogue: 0,0:47:41.41,0:47:43.88,EN,,0,0,0,,This is a little device.
Dialogue: 0,0:47:43.90,0:47:44.97,EN,,0,0,0,,This is a little stream machine
Dialogue: 0,0:47:45.50,0:47:46.83,EN,,0,0,0,,invented by Eric Grimson
Dialogue: 0,0:47:47.60,0:47:49.24,EN,,0,0,0,,who's been teaching this course at MIT.
Dialogue: 0,0:47:49.83,0:47:52.51,EN,,0,0,0,,And the image is ... here's a stream of stuff,
Dialogue: 0,0:47:52.54,0:47:53.82,EN,,0,0,0,,like a whole bunch of the integers.
Dialogue: 0,0:47:54.78,0:47:56.33,EN,,0,0,0,,And here's some processing elements.
Dialogue: 0,0:47:58.70,0:48:02.60,EN,,0,0,0,,And if, say, it's filter of filter of map, or something.
Dialogue: 0,0:48:03.98,0:48:09.18,EN,,0,0,0,,And if I really tried to implement that with streams as lists,
Dialogue: 0,0:48:09.24,0:48:11.26,EN,,0,0,0,,what I'd say is, well, I've got this list of things,
Dialogue: 0,0:48:11.47,0:48:12.67,EN,,0,0,0,,and now I do the first filter.
Dialogue: 0,0:48:12.67,0:48:14.07,EN,,0,0,0,,So I sort of do all this processing.
Dialogue: 0,0:48:14.88,0:48:15.77,EN,,0,0,0,,And I take this
Dialogue: 0,0:48:16.32,0:48:19.21,EN,,0,0,0,,and I process and I process and I process and I process.
Dialogue: 0,0:48:19.61,0:48:21.05,EN,,0,0,0,,And now I'm got this new stream.
Dialogue: 0,0:48:21.63,0:48:24.07,EN,,0,0,0,,Right? Now I take that result in my hand someplace.
Dialogue: 0,0:48:24.07,0:48:25.26,EN,,0,0,0,,And I put that through the second one.
Dialogue: 0,0:48:25.56,0:48:26.94,EN,,0,0,0,,And I process the whole thing.
Dialogue: 0,0:48:28.27,0:48:29.51,EN,,0,0,0,,And there's this new stream.
Dialogue: 0,0:48:32.13,0:48:33.36,EN,,0,0,0,,And then I take the result
Dialogue: 0,0:48:34.28,0:48:36.36,EN,,0,0,0,,and I put it all the way through this one the same way.
Dialogue: 0,0:48:36.36,0:48:40.99,EN,,0,0,0,,That's what would happen to these stream programs
Dialogue: 0,0:48:41.69,0:48:42.97,EN,,0,0,0,,if streams were just lists.
Dialogue: 0,0:48:43.86,0:48:45.64,EN,,0,0,0,,But in fact, streams aren't lists, they're streams.
Dialogue: 0,0:48:45.82,0:48:48.11,EN,,0,0,0,,And the image you should have is something a little bit more like this.
Dialogue: 0,0:48:50.23,0:48:52.52,EN,,0,0,0,,I've got these gadgets connected up
Dialogue: 0,0:48:55.26,0:48:56.76,EN,,0,0,0,,by this data that's flowing out of them.
Dialogue: 0,0:49:00.33,0:49:02.30,EN,,0,0,0,,And here's my original source of the streams.
Dialogue: 0,0:49:02.32,0:49:02.92,EN,,0,0,0,,It might be
Dialogue: 0,0:49:04.19,0:49:05.72,EN,,0,0,0,,starting to generate the integers.
Dialogue: 0,0:49:05.98,0:49:07.39,EN,,0,0,0,,And now, what happens if I want a result?
Dialogue: 0,0:49:07.58,0:49:08.91,EN,,0,0,0,,I tug on the end here.
Dialogue: 0,0:49:10.20,0:49:11.07,EN,,0,0,0,,And this element says,
Dialogue: 0,0:49:11.08,0:49:12.20,EN,,0,0,0,,gee, I need some more data.
Dialogue: 0,0:49:13.09,0:49:15.52,EN,,0,0,0,,So it's sort of, this one comes here and tugs on that one.
Dialogue: 0,0:49:15.83,0:49:17.39,EN,,0,0,0,,And it says, gee, I need some more data.
Dialogue: 0,0:49:17.89,0:49:19.56,EN,,0,0,0,,And this one tugs on this thing,
Dialogue: 0,0:49:19.56,0:49:20.28,EN,,0,0,0,,which might be a filter,
Dialogue: 0,0:49:20.28,0:49:21.40,EN,,0,0,0,,and says, gee, I need some more data.
Dialogue: 0,0:49:21.64,0:49:23.15,EN,,0,0,0,,And only as much of this
Dialogue: 0,0:49:23.53,0:49:25.56,EN,,0,0,0,,thing at the end here gets generated as I tugged.
Dialogue: 0,0:49:25.78,0:49:28.30,EN,,0,0,0,,And only as much of this stuff goes through the processing units
Dialogue: 0,0:49:28.56,0:49:29.98,EN,,0,0,0,,as I'm pulling on the end I need.
Dialogue: 0,0:49:30.76,0:49:32.09,EN,,0,0,0,,That's the image you should have
Dialogue: 0,0:49:32.80,0:49:34.38,EN,,0,0,0,,of the difference between implementing
Dialogue: 0,0:49:34.56,0:49:35.92,EN,,0,0,0,,what we're actually going to do
Dialogue: 0,0:49:36.16,0:49:37.50,EN,,0,0,0,,and if streams were lists.
Dialogue: 0,0:49:40.78,0:49:42.14,EN,,0,0,0,,Well, how do we make this thing?
Dialogue: 0,0:49:42.35,0:49:43.32,EN,,0,0,0,,I hope you have the image.
Dialogue: 0,0:49:43.40,0:49:44.52,EN,,0,0,0,,The trick is how to make it.
Dialogue: 0,0:49:47.93,0:49:50.32,EN,,0,0,0,,We want to arrange for a stream
Dialogue: 0,0:49:50.41,0:49:51.58,EN,,0,0,0,,to be a data structure
Dialogue: 0,0:49:52.00,0:49:54.22,EN,,0,0,0,,that sorts of computes itself incrementally,
Dialogue: 0,0:49:54.22,0:49:56.22,EN,,0,0,0,,sort of on-demand data structure.
Dialogue: 0,0:49:58.96,0:50:00.51,EN,,0,0,0,,Right? And the basic idea
Dialogue: 0,0:50:00.97,0:50:02.70,EN,,0,0,0,,is again, one of the very basic ideas
Dialogue: 0,0:50:02.72,0:50:04.12,EN,,0,0,0,,that we're seeing throughout the whole course.
Dialogue: 0,0:50:04.49,0:50:05.00,EN,,0,0,0,,And that is
Dialogue: 0,0:50:05.52,0:50:06.97,EN,,0,0,0,,that there's not a firm distinction
Dialogue: 0,0:50:06.99,0:50:08.44,EN,,0,0,0,,between programs and data.
Dialogue: 0,0:50:09.24,0:50:10.54,EN,,0,0,0,,So what a stream is going to be
Dialogue: 0,0:50:10.59,0:50:13.40,EN,,0,0,0,,is simultaneously this data structure that you think of,
Dialogue: 0,0:50:13.45,0:50:15.92,EN,,0,0,0,,like the stream of the leaves of this tree.
Dialogue: 0,0:50:16.86,0:50:17.85,EN,,0,0,0,,But at the same time,
Dialogue: 0,0:50:17.85,0:50:19.32,EN,,0,0,0,,it's going to be a very clever procedure
Dialogue: 0,0:50:20.24,0:50:22.22,EN,,0,0,0,,that has the method of computing in it.
Dialogue: 0,0:50:23.74,0:50:25.93,EN,,0,0,0,,Well, let me try this.
Dialogue: 0,0:50:25.93,0:50:26.62,EN,,0,0,0,,It's going to turn out
Dialogue: 0,0:50:26.80,0:50:28.33,EN,,0,0,0,,that we don't need any more mechanism.
Dialogue: 0,0:50:28.46,0:50:29.87,EN,,0,0,0,,We already have everything we need
Dialogue: 0,0:50:30.14,0:50:30.99,EN,,0,0,0,,simply from the fact
Dialogue: 0,0:50:31.02,0:50:33.93,EN,,0,0,0,,that we know how to handle procedures as first-class objects.
Dialogue: 0,0:50:35.46,0:50:36.88,EN,,0,0,0,,Well, let's go back to the key.
Dialogue: 0,0:50:36.88,0:50:39.03,EN,,0,0,0,,The key is, remember, we had these operations.
Dialogue: 0,0:50:39.03,0:50:47.52,EN,,0,0,0,,CONS-stream and head and tail.
Dialogue: 0,0:50:48.08,0:50:49.36,EN,,0,0,0,,When I started, I said
Dialogue: 0,0:50:49.92,0:50:51.36,EN,,0,0,0,,you can think about this as CONS
Dialogue: 0,0:50:51.40,0:50:52.62,EN,,0,0,0,,and think about this as CAR
Dialogue: 0,0:50:52.62,0:50:53.52,EN,,0,0,0,,and think about that as CDR
Dialogue: 0,0:50:53.55,0:50:54.16,EN,,0,0,0,,but it's not.
Dialogue: 0,0:50:55.08,0:50:56.32,EN,,0,0,0,,Now, let's look at what they really are.
Dialogue: 0,0:50:57.71,0:51:05.84,EN,,0,0,0,,Well, CONS-stream of x and y
Dialogue: 0,0:51:07.48,0:51:17.79,EN,,0,0,0,,is going to be an abbreviation for the following thing.
Dialogue: 0,0:51:19.54,0:51:28.32,EN,,0,0,0,,CONS form a pair, ordinary CONS, of x to a thing called delay of y.
Dialogue: 0,0:51:31.68,0:51:33.53,EN,,0,0,0,,And before I explain that, let me go and write the rest.
Dialogue: 0,0:51:34.52,0:51:35.53,EN,,0,0,0,,The head of a stream
Dialogue: 0,0:51:38.09,0:51:39.79,EN,,0,0,0,,is going to be just the CAR.
Dialogue: 0,0:51:42.38,0:51:44.25,EN,,0,0,0,,And the tail of a stream
Dialogue: 0,0:51:46.68,0:51:54.60,EN,,0,0,0,,is going to be a thing called force the CDR of the stream.
Dialogue: 0,0:51:56.12,0:51:57.04,EN,,0,0,0,,Now let me explain this.
Dialogue: 0,0:51:58.06,0:51:59.88,EN,,0,0,0,,Delay is going to be a special magic thing.
Dialogue: 0,0:52:01.42,0:52:02.33,EN,,0,0,0,,What delay does
Dialogue: 0,0:52:03.85,0:52:05.31,EN,,0,0,0,,is take an expression
Dialogue: 0,0:52:05.50,0:52:06.86,EN,,0,0,0,,and produce a promise
Dialogue: 0,0:52:07.12,0:52:09.15,EN,,0,0,0,,to compute that expression when you ask for it.
Dialogue: 0,0:52:10.60,0:52:11.98,EN,,0,0,0,,It doesn't do any computation here.
Dialogue: 0,0:52:11.98,0:52:14.32,EN,,0,0,0,,Just sort of... It just gives you a rain check.
Dialogue: 0,0:52:14.82,0:52:16.20,EN,,0,0,0,,It produces a promise.
Dialogue: 0,0:52:17.11,0:52:18.20,EN,,0,0,0,,And CONS-stream says
Dialogue: 0,0:52:18.81,0:52:21.96,EN,,0,0,0,,I'm going to put together in a pair x
Dialogue: 0,0:52:23.31,0:52:25.36,EN,,0,0,0,,and a promise to compute y.
Dialogue: 0,0:52:28.23,0:52:28.99,EN,,0,0,0,,Now, if I want the head,
Dialogue: 0,0:52:28.99,0:52:30.75,EN,,0,0,0,,that's just the CAR that I put in the pair.
Dialogue: 0,0:52:31.84,0:52:33.71,EN,,0,0,0,,And the key is that the tail is going to be--
Dialogue: 0,0:52:34.62,0:52:36.65,EN,,0,0,0,,force calls in that promise.
Dialogue: 0,0:52:38.22,0:52:39.88,EN,,0,0,0,,Force -- Tail says, well,
Dialogue: 0,0:52:40.03,0:52:41.02,EN,,0,0,0,,well, take that promise
Dialogue: 0,0:52:41.85,0:52:44.52,EN,,0,0,0,,and now call in that promise.
Dialogue: 0,0:52:44.56,0:52:46.03,EN,,0,0,0,,And then we compute that thing.
Dialogue: 0,0:52:47.69,0:52:48.72,EN,,0,0,0,,That's how this is going to work.
Dialogue: 0,0:52:48.74,0:52:51.55,EN,,0,0,0,,That's what CONS-stream, head, and tail really are.
Dialogue: 0,0:52:54.60,0:52:55.57,EN,,0,0,0,,Now, let's see how this works.
Dialogue: 0,0:52:55.57,0:52:57.50,EN,,0,0,0,,And we'll go through this fairly carefully. Let's --
Dialogue: 0,0:52:58.76,0:53:00.62,EN,,0,0,0,,We're going to see how this
Dialogue: 0,0:53:01.32,0:53:03.66,EN,,0,0,0,,example of computing the second prime
Dialogue: 0,0:53:05.50,0:53:07.16,EN,,0,0,0,,right? between 10,000 and a million.
Dialogue: 0,0:53:08.65,0:53:12.03,EN,,0,0,0,,OK, so we start off and we have this expression.
Dialogue: 0,0:53:15.36,0:53:16.62,EN,,0,0,0,,Right? The second prime--
Dialogue: 0,0:53:16.64,0:53:21.90,EN,,0,0,0,,the head of the tail of the result of filtering for primality
Dialogue: 0,0:53:22.83,0:53:25.31,EN,,0,0,0,,the integers between 10,000 and 1 million.
Dialogue: 0,0:53:26.71,0:53:27.61,EN,,0,0,0,,Now, what is that?
Dialogue: 0,0:53:28.40,0:53:29.20,EN,,0,0,0,,What that is,
Dialogue: 0,0:53:31.63,0:53:34.17,EN,,0,0,0,,that interval between 10,000 and 1 million,
Dialogue: 0,0:53:35.72,0:53:37.32,EN,,0,0,0,,well, if you trace through enumerate interval,
Dialogue: 0,0:53:37.34,0:53:38.78,EN,,0,0,0,,there builds a CONS-stream.
Dialogue: 0,0:53:39.92,0:53:41.39,EN,,0,0,0,,And the CONS-stream is
Dialogue: 0,0:53:41.96,0:53:43.61,EN,,0,0,0,,the CONS of 10,000
Dialogue: 0,0:53:44.51,0:53:48.92,EN,,0,0,0,,to a promise to compute the integers between 10,001 and 1 million.
Dialogue: 0,0:53:54.00,0:53:55.75,EN,,0,0,0,,Okay? So that's what this expression is.
Dialogue: 0,0:53:55.75,0:53:57.32,EN,,0,0,0,,Here I'm using the substitution model.
Dialogue: 0,0:53:57.64,0:53:59.32,EN,,0,0,0,,And we can use the substitution model
Dialogue: 0,0:53:59.34,0:54:01.01,EN,,0,0,0,,because we don't have side effects and state.
Dialogue: 0,0:54:03.56,0:54:06.38,EN,,0,0,0,,Okay? So I have CONS of 10,000
Dialogue: 0,0:54:06.41,0:54:08.27,EN,,0,0,0,,to a promise to compute the rest of the integers.
Dialogue: 0,0:54:08.32,0:54:10.49,EN,,0,0,0,,So only one integer, so far, got enumerated.
Dialogue: 0,0:54:14.38,0:54:16.96,EN,,0,0,0,,Well, I'm going to filter that thing for primality.
Dialogue: 0,0:54:19.44,0:54:21.90,EN,,0,0,0,,Again, you go back and look at the filter code.
Dialogue: 0,0:54:22.36,0:54:24.46,EN,,0,0,0,,What the filter will first do is test the head.
Dialogue: 0,0:54:25.46,0:54:28.25,EN,,0,0,0,,So in this case, the filter will test 10,000
Dialogue: 0,0:54:30.30,0:54:32.97,EN,,0,0,0,,oh, 10,000's not prime.
Dialogue: 0,0:54:33.50,0:54:35.85,EN,,0,0,0,,Therefore, what I have to do recursively
Dialogue: 0,0:54:36.25,0:54:37.39,EN,,0,0,0,,is filter the tail.
Dialogue: 0,0:54:39.22,0:54:40.14,EN,,0,0,0,,And what's the tail of it,
Dialogue: 0,0:54:40.16,0:54:43.76,EN,,0,0,0,,well, that's the tail of this pair with a promise in it.
Dialogue: 0,0:54:46.34,0:54:48.06,EN,,0,0,0,,Tail now comes in and says,
Dialogue: 0,0:54:48.28,0:54:49.50,EN,,0,0,0,,well, I'm going to force that.
Dialogue: 0,0:54:49.68,0:54:50.94,EN,,0,0,0,,I'm going to force that promise,
Dialogue: 0,0:54:52.30,0:54:54.36,EN,,0,0,0,,which means now I'm going to compute
Dialogue: 0,0:54:55.58,0:54:57.96,EN,,0,0,0,,the integers between 10,001 and 1 million.
Dialogue: 0,0:55:00.80,0:55:02.97,EN,,0,0,0,,OK? So this filter now is looking at that.
Dialogue: 0,0:55:07.81,0:55:08.92,EN,,0,0,0,,That enumerate itself,
Dialogue: 0,0:55:08.94,0:55:11.23,EN,,0,0,0,,now we're back in the original enumerate situation.
Dialogue: 0,0:55:11.96,0:55:13.00,EN,,0,0,0,,The enumerate is
Dialogue: 0,0:55:14.12,0:55:16.44,EN,,0,0,0,,CONS of the first thing, 10,001,
Dialogue: 0,0:55:16.60,0:55:18.20,EN,,0,0,0,,onto a promise to compute the rest.
Dialogue: 0,0:55:19.74,0:55:22.75,EN,,0,0,0,,So now the primality filter is going to go look at 10,001.
Dialogue: 0,0:55:23.23,0:55:25.12,EN,,0,0,0,,It's going to decide if it likes that or not.
Dialogue: 0,0:55:25.12,0:55:27.08,EN,,0,0,0,,It turns out 10,001 isn't prime.
Dialogue: 0,0:55:27.55,0:55:29.61,EN,,0,0,0,,So it'll force it again and again and again.
Dialogue: 0,0:55:32.92,0:55:35.80,EN,,0,0,0,,And finally, I think the first prime it hits is 10,009.
Dialogue: 0,0:55:37.10,0:55:38.33,EN,,0,0,0,,And at that point, it'll stop.
Dialogue: 0,0:55:40.84,0:55:41.93,EN,,0,0,0,,And that will be the first prime,
Dialogue: 0,0:55:41.96,0:55:43.48,EN,,0,0,0,,and then eventually, it'll need the second prime.
Dialogue: 0,0:55:45.24,0:55:46.84,EN,,0,0,0,,So at that point, it will go again.
Dialogue: 0,0:55:47.03,0:55:48.25,EN,,0,0,0,,So you see what happens is that
Dialogue: 0,0:55:48.52,0:55:50.49,EN,,0,0,0,,no more gets generated
Dialogue: 0,0:55:51.85,0:55:52.91,EN,,0,0,0,,than you actually need.
Dialogue: 0,0:55:56.48,0:55:59.92,EN,,0,0,0,,That enumerator is not going to generate any more integers
Dialogue: 0,0:56:00.12,0:56:01.45,EN,,0,0,0,,than the filter asks it for
Dialogue: 0,0:56:01.47,0:56:03.45,EN,,0,0,0,,as it's pulling in things to check for primality.
Dialogue: 0,0:56:04.70,0:56:06.51,EN,,0,0,0,,And the filter is not going to generate
Dialogue: 0,0:56:06.54,0:56:08.04,EN,,0,0,0,,any more stuff than you ask it for,
Dialogue: 0,0:56:08.06,0:56:09.10,EN,,0,0,0,,which is the head of the tail.
Dialogue: 0,0:56:11.61,0:56:13.26,EN,,0,0,0,,You see, what's happened is
Dialogue: 0,0:56:14.70,0:56:18.24,EN,,0,0,0,,we've put that mixing of generation and test
Dialogue: 0,0:56:18.67,0:56:20.65,EN,,0,0,0,,into what actually happens in the computer,
Dialogue: 0,0:56:21.52,0:56:22.67,EN,,0,0,0,,even though
Dialogue: 0,0:56:23.18,0:56:25.63,EN,,0,0,0,,that's not apparently what's happening from looking at our programs.
Dialogue: 0,0:56:28.12,0:56:29.40,EN,,0,0,0,,OK, well, that seemed easy.
Dialogue: 0,0:56:30.23,0:56:32.67,EN,,0,0,0,,All of this mechanism got put into this magic delay.
Dialogue: 0,0:56:33.68,0:56:35.66,EN,,0,0,0,,So you're saying, gee, that must be where the magic is.
Dialogue: 0,0:56:36.90,0:56:38.57,EN,,0,0,0,,But see there's no magic there either.
Dialogue: 0,0:56:39.07,0:56:39.98,EN,,0,0,0,,You know what delay is.
Dialogue: 0,0:56:40.61,0:56:45.07,EN,,0,0,0,,Delay on some expression
Dialogue: 0,0:56:48.25,0:56:50.04,EN,,0,0,0,,is just an abbreviation for--
Dialogue: 0,0:56:53.36,0:56:55.63,EN,,0,0,0,,well, what's a promise to compute an expression?
Dialogue: 0,0:56:56.49,0:57:01.12,EN,,0,0,0,,Lambda of nil, procedure of no arguments, which is that expression.
Dialogue: 0,0:57:02.83,0:57:03.84,EN,,0,0,0,,Right? That's what a procedure is.
Dialogue: 0,0:57:03.98,0:57:05.53,EN,,0,0,0,,It says I'm going to compute an expression.
Dialogue: 0,0:57:06.05,0:57:06.73,EN,,0,0,0,,What's force?
Dialogue: 0,0:57:07.34,0:57:10.80,EN,,0,0,0,,Right, how do I take up a promise?
Dialogue: 0,0:57:10.80,0:57:14.11,EN,,0,0,0,,Well, force of some procedure, a promise,
Dialogue: 0,0:57:14.78,0:57:15.40,EN,,0,0,0,,is just run it.
Dialogue: 0,0:57:19.23,0:57:19.56,EN,,0,0,0,,Done.
Dialogue: 0,0:57:20.24,0:57:21.37,EN,,0,0,0,,So there's no magic there at all.
Dialogue: 0,0:57:23.52,0:57:24.24,EN,,0,0,0,,Well, what have we done?
Dialogue: 0,0:57:26.44,0:57:27.50,EN,,0,0,0,,We said the old style,
Dialogue: 0,0:57:28.14,0:57:30.81,EN,,0,0,0,,traditional style of programming is more efficient.
Dialogue: 0,0:57:30.96,0:57:33.92,EN,,0,0,0,,And the stream thing is more perspicacious.
Dialogue: 0,0:57:35.50,0:57:38.72,EN,,0,0,0,,And we managed to make the stream procedures
Dialogue: 0,0:57:38.81,0:57:43.23,EN,,0,0,0,,run like the other procedures by using delay.
Dialogue: 0,0:57:43.35,0:57:46.43,EN,,0,0,0,,And the thing that delay did for us was to de-couple
Dialogue: 0,0:57:46.68,0:57:50.40,EN,,0,0,0,,the apparent order of events in our programs
Dialogue: 0,0:57:51.21,0:57:53.84,EN,,0,0,0,,from the actual order of events that happened in the machine.
Dialogue: 0,0:57:54.44,0:57:55.93,EN,,0,0,0,,That's really what delay is doing.
Dialogue: 0,0:57:57.15,0:57:58.29,EN,,0,0,0,,That's exactly the whole point.
Dialogue: 0,0:57:58.29,0:58:01.92,EN,,0,0,0,,We've given up, right, we've given up the idea
Dialogue: 0,0:58:02.30,0:58:04.17,EN,,0,0,0,,that our procedures, as they run,
Dialogue: 0,0:58:04.67,0:58:05.95,EN,,0,0,0,,or as we look at them,
Dialogue: 0,0:58:06.33,0:58:08.25,EN,,0,0,0,,mirror some clear notion of time.
Dialogue: 0,0:58:09.45,0:58:10.57,EN,,0,0,0,,And by giving that up,
Dialogue: 0,0:58:11.21,0:58:13.32,EN,,0,0,0,,we give delay the freedom to arrange the order
Dialogue: 0,0:58:13.34,0:58:15.20,EN,,0,0,0,,of events in the computation the way it likes.
Dialogue: 0,0:58:16.69,0:58:17.61,EN,,0,0,0,,That's the whole idea.
Dialogue: 0,0:58:17.61,0:58:19.45,EN,,0,0,0,,We de-couple the apparent order
Dialogue: 0,0:58:19.95,0:58:21.13,EN,,0,0,0,,of events in our programs
Dialogue: 0,0:58:21.16,0:58:22.89,EN,,0,0,0,,from the actual order of events in the computer.
Dialogue: 0,0:58:24.09,0:58:25.77,EN,,0,0,0,,OK, well there's one more detail.
Dialogue: 0,0:58:25.77,0:58:27.21,EN,,0,0,0,,It's just a technical detail,
Dialogue: 0,0:58:27.21,0:58:28.43,EN,,0,0,0,,but it's actually an important one.
Dialogue: 0,0:58:29.73,0:58:32.01,EN,,0,0,0,,As you run through these recursive programs unwinding,
Dialogue: 0,0:58:32.16,0:58:33.58,EN,,0,0,0,,you'll see a lot of things that look like
Dialogue: 0,0:58:33.64,0:58:37.87,EN,,0,0,0,,tail of the tail of the tail.
Dialogue: 0,0:58:39.20,0:58:41.02,EN,,0,0,0,,Right. That's the kind of thing that would happen
Dialogue: 0,0:58:41.02,0:58:42.88,EN,,0,0,0,,as I go CONSing down a stream all the way.
Dialogue: 0,0:58:43.86,0:58:46.09,EN,,0,0,0,,And if each time I'm doing that,
Dialogue: 0,0:58:46.14,0:58:47.58,EN,,0,0,0,,each time to compute a tail,
Dialogue: 0,0:58:48.22,0:58:50.88,EN,,0,0,0,,I evaluate a procedure
Dialogue: 0,0:58:51.07,0:58:53.07,EN,,0,0,0,,which then has to go re-compute its tail,
Dialogue: 0,0:58:53.10,0:58:55.40,EN,,0,0,0,,and re-compute its tail and recompute its tail each time,
Dialogue: 0,0:58:55.50,0:58:56.88,EN,,0,0,0,,you can see that's very inefficient
Dialogue: 0,0:58:57.77,0:59:00.56,EN,,0,0,0,,compared to just having a list where the elements are all there,
Dialogue: 0,0:59:01.16,0:59:04.00,EN,,0,0,0,,and I don't have to re-compute each tail every time I get the next tail.
Dialogue: 0,0:59:05.29,0:59:08.28,EN,,0,0,0,,So there's one little hack
Dialogue: 0,0:59:09.66,0:59:13.13,EN,,0,0,0,,to slightly change the abbreviation, change what delay is
Dialogue: 0,0:59:14.96,0:59:18.20,EN,,0,0,0,,and make it a thing which is-- I'll write it this way.
Dialogue: 0,0:59:19.68,0:59:22.04,EN,,0,0,0,,Delay -- The actual implementation,
Dialogue: 0,0:59:24.52,0:59:27.93,EN,,0,0,0,,delay is an abbreviation for this thing,
Dialogue: 0,0:59:28.11,0:59:30.86,EN,,0,0,0,,memo-proc of a procedure.
Dialogue: 0,0:59:31.00,0:59:34.06,EN,,0,0,0,,Memo-proc is a special thing that transforms a procedure.
Dialogue: 0,0:59:35.15,0:59:37.80,EN,,0,0,0,,What it does is it takes a procedure of no arguments
Dialogue: 0,0:59:39.02,0:59:41.05,EN,,0,0,0,,and it transforms it into a procedure
Dialogue: 0,0:59:41.36,0:59:43.55,EN,,0,0,0,,that'll only have to do its computation once.
Dialogue: 0,0:59:45.10,0:59:47.45,EN,,0,0,0,,And what I mean by that is, you give it a procedure.
Dialogue: 0,0:59:48.70,0:59:50.86,EN,,0,0,0,,The result of memo-proc will be a new procedure,
Dialogue: 0,0:59:51.39,0:59:53.00,EN,,0,0,0,,which the first time you call it,
Dialogue: 0,0:59:53.71,0:59:55.07,EN,,0,0,0,,will run the original procedure,
Dialogue: 0,0:59:55.31,0:59:56.91,EN,,0,0,0,,remember what result it got,
Dialogue: 0,0:59:58.56,1:00:00.68,EN,,0,0,0,,and then from ever on after, when you call it,
Dialogue: 0,1:00:00.68,1:00:02.17,EN,,0,0,0,,it just won't have to do the computation.
Dialogue: 0,1:00:02.19,1:00:04.43,EN,,0,0,0,,It will have cached that result someplace.
Dialogue: 0,1:00:05.20,1:00:06.92,EN,,0,0,0,,And here's an implementation of memo-proc.
Dialogue: 0,1:00:11.21,1:00:12.71,EN,,0,0,0,,Once you have the idea, it's easy to implement.
Dialogue: 0,1:00:12.71,1:00:16.76,EN,,0,0,0,,Memo-proc is this little thing that has two little flags in there.
Dialogue: 0,1:00:17.39,1:00:19.20,EN,,0,0,0,,It says, have I already been run?
Dialogue: 0,1:00:20.32,1:00:22.48,EN,,0,0,0,,And initially it says, no, I haven't already been run.
Dialogue: 0,1:00:23.62,1:00:27.04,EN,,0,0,0,,And what was the result I got the last time I was run?
Dialogue: 0,1:00:29.07,1:00:31.07,EN,,0,0,0,,So memo-proc takes a procedure called proc,
Dialogue: 0,1:00:31.56,1:00:34.01,EN,,0,0,0,,and it returns a new procedure of no arguments.
Dialogue: 0,1:00:34.36,1:00:36.38,EN,,0,0,0,,Proc is supposed to be a procedure of no arguments.
Dialogue: 0,1:00:38.61,1:00:41.37,EN,,0,0,0,,And it says, oh, if I'm not already run,
Dialogue: 0,1:00:42.59,1:00:44.06,EN,,0,0,0,,then I'm going to do a sequence of things.
Dialogue: 0,1:00:44.43,1:00:46.56,EN,,0,0,0,,I'm going to compute proc,
Dialogue: 0,1:00:47.50,1:00:48.45,EN,,0,0,0,,I'm going to save that.
Dialogue: 0,1:00:48.45,1:00:50.48,EN,,0,0,0,,I'm going to stash that in the variable result.
Dialogue: 0,1:00:51.14,1:00:53.90,EN,,0,0,0,,I'm going to make a note to myself that I've already been run,
Dialogue: 0,1:00:54.28,1:00:55.47,EN,,0,0,0,,and then I'll return the result.
Dialogue: 0,1:00:56.61,1:00:59.01,EN,,0,0,0,,So that's if you compute it if it's not already run.
Dialogue: 0,1:00:59.01,1:01:01.88,EN,,0,0,0,,If you call it and it's already been run, it just returns the result.
Dialogue: 0,1:01:03.42,1:01:07.12,EN,,0,0,0,,So that's a little clever hack called memoization.
Dialogue: 0,1:01:08.40,1:01:09.13,EN,,0,0,0,,And in this case,
Dialogue: 0,1:01:10.35,1:01:14.14,EN,,0,0,0,,it short circuits having to re-compute the tail of the tail of the tail of the tail of the tail.
Dialogue: 0,1:01:15.27,1:01:17.81,EN,,0,0,0,,So there isn't even that kind of inefficiency.
Dialogue: 0,1:01:17.81,1:01:18.72,EN,,0,0,0,,And in fact, the streams
Dialogue: 0,1:01:19.20,1:01:22.75,EN,,0,0,0,,will run with pretty much the same efficiency as the other programs precisely.
Dialogue: 0,1:01:24.01,1:01:26.20,EN,,0,0,0,,And remember, again, the whole idea of this
Dialogue: 0,1:01:27.48,1:01:28.60,EN,,0,0,0,,is that we've used
Dialogue: 0,1:01:29.26,1:01:32.40,EN,,0,0,0,,the fact that there's no really good dividing line
Dialogue: 0,1:01:32.41,1:01:33.61,EN,,0,0,0,,between procedures and data.
Dialogue: 0,1:01:33.61,1:01:35.61,EN,,0,0,0,,We've written data structures that, in fact,
Dialogue: 0,1:01:36.00,1:01:37.31,EN,,0,0,0,,are sort of like procedures.
Dialogue: 0,1:01:38.76,1:01:40.73,EN,,0,0,0,,And what that's allowed us to do
Dialogue: 0,1:01:41.58,1:01:46.54,EN,,0,0,0,,is take an example of a common control structure,
Dialogue: 0,1:01:46.68,1:01:48.91,EN,,0,0,0,,in this place iteration.
Dialogue: 0,1:01:49.62,1:01:51.05,EN,,0,0,0,,And we've built a data structure
Dialogue: 0,1:01:51.32,1:01:52.84,EN,,0,0,0,,which, since itself is a procedure,
Dialogue: 0,1:01:52.86,1:01:55.12,EN,,0,0,0,,kind of has this iteration control structure in it.
Dialogue: 0,1:01:55.79,1:01:57.13,EN,,0,0,0,,And that's really what streams are.
Dialogue: 0,1:01:58.91,1:01:59.76,EN,,0,0,0,,OK, questions?
Dialogue: 0,1:02:03.95,1:02:05.84,EN,,0,0,0,,AUDIENCE: Your description of tail-tail-tail,
Dialogue: 0,1:02:05.85,1:02:07.16,EN,,0,0,0,,if I understand it correctly,
Dialogue: 0,1:02:07.28,1:02:10.76,EN,,0,0,0,,force is actually execution of a procedure,
Dialogue: 0,1:02:10.78,1:02:12.83,EN,,0,0,0,,if it's done without this memo-proc thing.
Dialogue: 0,1:02:12.89,1:02:13.15,EN,,0,0,0,,PROFESSOR: Right.
Dialogue: 0,1:02:13.44,1:02:16.38,EN,,0,0,0,,AUDIENCE: And you implied that memo-proc gets around that problem.
Dialogue: 0,1:02:16.38,1:02:18.73,EN,,0,0,0,,Doesn't it only get around it if
Dialogue: 0,1:02:19.34,1:02:22.19,EN,,0,0,0,,tail-tail-tail is always executing exactly the same--
Dialogue: 0,1:02:22.41,1:02:23.91,EN,,0,0,0,,PROFESSOR: Oh, that's-- sure.
Dialogue: 0,1:02:23.91,1:02:25.84,EN,,0,0,0,,AUDIENCE: I guess I missed that point.
Dialogue: 0,1:02:26.05,1:02:27.21,EN,,0,0,0,,PROFESSOR: Oh, sure. I mean the point is-- yeah.
Dialogue: 0,1:02:31.12,1:02:33.64,EN,,0,0,0,,Yeah, I mean I have to do a computation to get the answer.
Dialogue: 0,1:02:34.09,1:02:36.76,EN,,0,0,0,,But the point is, once I've found the tail of the stream,
Dialogue: 0,1:02:37.58,1:02:38.70,EN,,0,0,0,,to get the tail of the tail,
Dialogue: 0,1:02:38.70,1:02:40.51,EN,,0,0,0,,I shouldn't have had to re-compute the first tail.
Dialogue: 0,1:02:42.98,1:02:44.32,EN,,0,0,0,,See, and if I didn't use memo-proc,
Dialogue: 0,1:02:44.35,1:02:46.09,EN,,0,0,0,,that re-computation would have been done.
Dialogue: 0,1:02:46.46,1:02:47.13,EN,,0,0,0,,AUDIENCE: I understand now.
Dialogue: 0,1:02:50.83,1:02:52.56,EN,,0,0,0,,AUDIENCE: In one of your examples, you mentioned that
Dialogue: 0,1:02:52.60,1:02:54.22,EN,,0,0,0,,we were able to use the substitution model
Dialogue: 0,1:02:54.22,1:02:56.11,EN,,0,0,0,,because there are no side effects.
Dialogue: 0,1:02:56.83,1:03:00.73,EN,,0,0,0,,What if we had a signal processing unit--
Dialogue: 0,1:03:00.78,1:03:02.03,EN,,0,0,0,,if we had a side effect,
Dialogue: 0,1:03:02.04,1:03:03.04,EN,,0,0,0,,if we had a state?
Dialogue: 0,1:03:03.62,1:03:06.84,EN,,0,0,0,,Could we still practically build the stream model?
Dialogue: 0,1:03:08.46,1:03:10.59,EN,,0,0,0,,PROFESSOR: Hum... Maybe, That's a hard question.
Dialogue: 0,1:03:11.20,1:03:13.42,EN,,0,0,0,,I'm going to talk a little bit later about the places where
Dialogue: 0,1:03:14.36,1:03:18.24,EN,,0,0,0,,where substitution and side effects don't really mix very well.
Dialogue: 0,1:03:18.96,1:03:20.48,EN,,0,0,0,,But in general, I think the answer is
Dialogue: 0,1:03:20.49,1:03:21.63,EN,,0,0,0,,unless you're very careful,
Dialogue: 0,1:03:21.90,1:03:24.46,EN,,0,0,0,,any amount of side effect is going to mess up everything.
Dialogue: 0,1:03:35.04,1:03:38.25,EN,,0,0,0,,AUDIENCE: Sorry, I didn't quite understand the memo-proc operation. Uh...
Dialogue: 0,1:03:39.68,1:03:41.12,EN,,0,0,0,,When do you execute the lambda?
Dialogue: 0,1:03:41.99,1:03:43.21,EN,,0,0,0,,In other words,
Dialogue: 0,1:03:43.68,1:03:45.15,EN,,0,0,0,,when memo-proc is executed,
Dialogue: 0,1:03:45.18,1:03:47.71,EN,,0,0,0,,just this lambda expression is being generated.
Dialogue: 0,1:03:48.01,1:03:49.68,EN,,0,0,0,,But it's not clear to me when it's executed.
Dialogue: 0,1:03:50.39,1:03:51.12,EN,,0,0,0,,PROFESSOR: Right.
Dialogue: 0,1:03:51.35,1:03:52.68,EN,,0,0,0,,What memo-proc does-- remember,
Dialogue: 0,1:03:53.07,1:03:55.85,EN,,0,0,0,,the thing that's going into memo-proc, the thing proc,
Dialogue: 0,1:03:56.38,1:03:57.93,EN,,0,0,0,,is a procedure of no arguments.
Dialogue: 0,1:03:57.93,1:03:59.05,EN,,0,0,0,,And someday, you're going to call it.
Dialogue: 0,1:04:00.39,1:04:02.75,EN,,0,0,0,,Memo-proc translates that procedure
Dialogue: 0,1:04:02.75,1:04:04.56,EN,,0,0,0,,into another procedure of no arguments,
Dialogue: 0,1:04:04.59,1:04:05.80,EN,,0,0,0,,which someday you're going to call.
Dialogue: 0,1:04:06.62,1:04:07.42,EN,,0,0,0,,That's that lambda.
Dialogue: 0,1:04:09.89,1:04:14.08,EN,,0,0,0,,So here, where I initially built as my
Dialogue: 0,1:04:15.85,1:04:17.92,EN,,0,0,0,,I built as my tail of the stream,
Dialogue: 0,1:04:18.30,1:04:20.48,EN,,0,0,0,,say, this procedure of no arguments,
Dialogue: 0,1:04:20.51,1:04:21.61,EN,,0,0,0,,which someday I'll call.
Dialogue: 0,1:04:24.10,1:04:28.01,EN,,0,0,0,,Instead, I'm going to have the tail of the stream be memo-proc of it,
Dialogue: 0,1:04:28.12,1:04:29.24,EN,,0,0,0,,which someday I'll call.
Dialogue: 0,1:04:30.65,1:04:31.90,EN,,0,0,0,,So that lambda of nil,
Dialogue: 0,1:04:32.03,1:04:36.06,EN,,0,0,0,,that gets called when you call the memo-proc,
Dialogue: 0,1:04:38.97,1:04:40.96,EN,,0,0,0,,when you call the result of that memo-proc,
Dialogue: 0,1:04:40.97,1:04:42.28,EN,,0,0,0,,which would be ordinarily
Dialogue: 0,1:04:42.36,1:04:45.76,EN,,0,0,0,,when you would have called the original thing that you set it.
Dialogue: 0,1:04:47.64,1:04:48.86,EN,,0,0,0,,AUDIENCE: OK, my ask is
Dialogue: 0,1:04:48.86,1:04:50.86,EN,,0,0,0,,I had a feeling that when you call memo-proc,
Dialogue: 0,1:04:50.86,1:04:52.30,EN,,0,0,0,,you just return this lambda.
Dialogue: 0,1:04:52.61,1:04:53.07,EN,,0,0,0,,PROFESSOR: That's right.
Dialogue: 0,1:04:53.77,1:04:58.10,EN,,0,0,0,,When you call memo-proc, you return the lambda.
Dialogue: 0,1:04:58.10,1:04:59.84,EN,,0,0,0,,You never evaluate the expression at all,
Dialogue: 0,1:04:59.87,1:05:02.27,EN,,0,0,0,,until the first time that you would have evaluated it.
Dialogue: 0,1:05:07.76,1:05:09.10,EN,,0,0,0,,AUDIENCE: Do I understand it right
Dialogue: 0,1:05:09.18,1:05:11.40,EN,,0,0,0,,you actually have to build the list up,
Dialogue: 0,1:05:11.47,1:05:14.17,EN,,0,0,0,,but the elements of the list don't get evaluated?
Dialogue: 0,1:05:14.24,1:05:15.63,EN,,0,0,0,,The expressions don't get evaluated?
Dialogue: 0,1:05:15.63,1:05:18.54,EN,,0,0,0,,But at each stage, you actually are building a list.
Dialogue: 0,1:05:18.54,1:05:20.70,EN,,0,0,0,,PROFESSOR: That's-- I really should have said this.
Dialogue: 0,1:05:20.70,1:05:22.27,EN,,0,0,0,,That's a really good point.
Dialogue: 0,1:05:22.27,1:05:23.18,EN,,0,0,0,,No, it's not quite right.
Dialogue: 0,1:05:23.66,1:05:25.08,EN,,0,0,0,,See, cause what happens is this.
Dialogue: 0,1:05:25.08,1:05:26.35,EN,,0,0,0,,Let me draw this as pairs.
Dialogue: 0,1:05:26.89,1:05:28.03,EN,,0,0,0,,Suppose I'm going to make a big stream,
Dialogue: 0,1:05:28.96,1:05:30.12,EN,,0,0,0,,like enumerate interval,
Dialogue: 0,1:05:30.32,1:05:31.48,EN,,0,0,0,,1 through 1 billion.
Dialogue: 0,1:05:32.74,1:05:35.74,EN,,0,0,0,,What that is, is a pair
Dialogue: 0,1:05:39.34,1:05:43.36,EN,,0,0,0,,a 1 and a promise.
Dialogue: 0,1:05:46.73,1:05:47.89,EN,,0,0,0,,That's exactly what it is.
Dialogue: 0,1:05:47.89,1:05:48.76,EN,,0,0,0,,Nothing got built up.
Dialogue: 0,1:05:51.60,1:05:53.29,EN,,0,0,0,,When I go and force this,
Dialogue: 0,1:05:54.51,1:05:56.37,EN,,0,0,0,,and see, what happens?
Dialogue: 0,1:05:56.37,1:05:59.66,EN,,0,0,0,,Well, this thing is now also recursively a CONS.
Dialogue: 0,1:06:00.53,1:06:02.16,EN,,0,0,0,,So that this promise now is
Dialogue: 0,1:06:04.62,1:06:08.96,EN,,0,0,0,,the next thing, which is a 2 and a promise to do more.
Dialogue: 0,1:06:11.35,1:06:12.73,EN,,0,0,0,,And so on and so on and so on.
Dialogue: 0,1:06:14.47,1:06:17.63,EN,,0,0,0,,So nothing gets built up until you walk down the stream.
Dialogue: 0,1:06:18.20,1:06:19.58,EN,,0,0,0,,Because what's sitting here is not the list,
Dialogue: 0,1:06:20.03,1:06:21.48,EN,,0,0,0,,but a promise to generate the list.
Dialogue: 0,1:06:23.39,1:06:25.50,EN,,0,0,0,,And by promise, technically I mean procedure.
Dialogue: 0,1:06:27.80,1:06:29.10,EN,,0,0,0,,So it doesn't get built up.
Dialogue: 0,1:06:30.76,1:06:32.72,EN,,0,0,0,,Yeah, I should have said that before that.
Dialogue: 0,1:06:34.28,1:06:35.34,EN,,0,0,0,,OK. That you. Let's take a break.
Dialogue: 0,0:00:00.01,0:00:02.46,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作
Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释
Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium)
Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞
Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead)
Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授
Dialogue: 0,0:00:10.10,0:00:14.60,Declare,,0,0,0,,{\an2\fad(500,500)}流 I
Dialogue: 0,0:00:18.55,0:00:21.84,Default,,0,0,0,,上次Gerry教授揭晓了秘密
Dialogue: 0,0:00:22.49,0:00:24.60,Default,,0,0,0,,他介绍了赋值的概念
Dialogue: 0,0:00:26.35,0:00:33.61,Default,,0,0,0,,赋值与状态
Dialogue: 0,0:00:37.48,0:00:40.03,Default,,0,0,0,,正如我们所见
Dialogue: 0,0:00:40.72,0:00:43.16,Default,,0,0,0,,将赋值和状态引入到语言中
Dialogue: 0,0:00:43.16,0:00:44.41,Default,,0,0,0,,后果相当糟糕
Dialogue: 0,0:00:45.08,0:00:48.62,Default,,0,0,0,,首先 代换模型不再能够描述求值过程了
Dialogue: 0,0:00:49.13,0:00:52.48,Default,,0,0,0,,为了解释程序中语句的语义
Dialogue: 0,0:00:52.48,0:00:54.27,Default,,0,0,0,,我们不得不使用更复杂的环境模型
Dialogue: 0,0:00:54.28,0:00:57.24,Default,,0,0,0,,也就是一种跟图表相关的非常机械的东西
Dialogue: 0,0:00:58.46,0:01:00.12,Default,,0,0,0,,并且 这不单纯地是一个技术上的问题
Dialogue: 0,0:01:00.26,0:01:03.28,Default,,0,0,0,,并不是因为代换模型在这里不怎么有效
Dialogue: 0,0:01:03.60,0:01:05.68,Default,,0,0,0,,所以我们得想些其它办法
Dialogue: 0,0:01:05.71,0:01:09.79,Default,,0,0,0,,而是代换模型这类机制都不再起效
Dialogue: 0,0:01:10.73,0:01:13.32,Default,,0,0,0,,这是因为突然间 一个变量
Dialogue: 0,0:01:14.12,0:01:16.92,Default,,0,0,0,,不再是代表着一个值了
Dialogue: 0,0:01:17.95,0:01:21.76,Default,,0,0,0,,现在 变量用于指明一个位置
Dialogue: 0,0:01:22.40,0:01:23.34,Default,,0,0,0,,一个存放值的位置
Dialogue: 0,0:01:23.63,0:01:26.14,Default,,0,0,0,,并且 这个位置的值可以发生改变
Dialogue: 0,0:01:30.28,0:01:34.09,Default,,0,0,0,,比如像 (F X) 这样的表达式
Dialogue: 0,0:01:37.36,0:01:39.64,Default,,0,0,0,,就可能含有副作用
Dialogue: 0,0:01:40.41,0:01:42.60,Default,,0,0,0,,如果我们执行 (F X) 得到某个值
Dialogue: 0,0:01:43.18,0:01:45.34,Default,,0,0,0,,之后我们再次执行 (F X)
Dialogue: 0,0:01:47.24,0:01:48.43,Default,,0,0,0,,可能因为求值的顺序
Dialogue: 0,0:01:48.86,0:01:49.74,Default,,0,0,0,,而得到不同的值
Dialogue: 0,0:01:49.76,0:01:52.14,Default,,0,0,0,,所以突然间 我们不能仅仅关注于值
Dialogue: 0,0:01:52.52,0:01:53.60,Default,,0,0,0,,也要关注时序
Dialogue: 0,0:01:57.97,0:01:59.98,Default,,0,0,0,,序对也不仅仅
Dialogue: 0,0:02:00.65,0:02:02.52,Default,,0,0,0,,只是它的CAR和CDR部分
Dialogue: 0,0:02:02.52,0:02:05.61,Default,,0,0,0,,不是作为CAR部分和CDR部分的别称
Dialogue: 0,0:02:05.80,0:02:07.05,Default,,0,0,0,,它也有自己的“身份”
Dialogue: 0,0:02:08.44,0:02:11.65,Default,,0,0,0,,序对具有“身份”
Dialogue: 0,0:02:11.65,0:02:12.59,Default,,0,0,0,,它是一个对象
Dialogue: 0,0:02:21.33,0:02:25.15,Default,,0,0,0,,两个具有相同CAR和CDR部分的序对
Dialogue: 0,0:02:25.40,0:02:27.05,Default,,0,0,0,,可能相同也可能不同
Dialogue: 0,0:02:27.87,0:02:30.51,Default,,0,0,0,,因为这之中可能存在“共享”
Dialogue: 0,0:02:34.96,0:02:39.45,Default,,0,0,0,,一引入赋值 这些就变成要考虑的问题了
Dialogue: 0,0:02:40.48,0:02:43.98,Default,,0,0,0,,确实 这和我们说讲代换的时候差别悬殊
Dialogue: 0,0:02:45.04,0:02:48.91,Default,,0,0,0,,技术上来看 我们思考起来更加困难了
Dialogue: 0,0:02:48.94,0:02:53.45,Default,,0,0,0,,因为我们必须相当机械地思考程序语言
Dialogue: 0,0:02:53.47,0:02:55.34,Default,,0,0,0,,而不能仅仅用数学的方式来思考
Dialogue: 0,0:02:55.71,0:02:58.60,Default,,0,0,0,,我们也会遇到哲学问题
Dialogue: 0,0:02:59.15,0:03:00.65,Default,,0,0,0,,我们会被这样的问题所困扰:
Dialogue: 0,0:03:00.67,0:03:02.38,Default,,0,0,0,,事物的“改变”指的是什么?
Dialogue: 0,0:03:02.38,0:03:03.77,Default,,0,0,0,,两个事物“同一”又如何判别?
Dialogue: 0,0:03:03.84,0:03:06.83,Default,,0,0,0,,并且 这也会给我们编程带来困扰
Dialogue: 0,0:03:07.47,0:03:08.54,Default,,0,0,0,,正如 Sussman 教授上节课中讲的那样
Dialogue: 0,0:03:08.56,0:03:12.20,Default,,0,0,0,,错误的表达式顺序和别名会产生BUG
Dialogue: 0,0:03:12.22,0:03:16.19,Default,,0,0,0,,这些问题在不需要考虑“对象”的语言中 是不存在的
Dialogue: 0,0:03:18.21,0:03:21.20,Default,,0,0,0,,我们是怎样陷入这样的困境的呢?
Dialogue: 0,0:03:24.01,0:03:27.20,Default,,0,0,0,,我们这样做的原因在于
Dialogue: 0,0:03:27.40,0:03:31.47,Default,,0,0,0,,我们想要构造模块化的系统
Dialogue: 0,0:03:35.15,0:03:37.69,Default,,0,0,0,,我们想把系统划分为
Dialogue: 0,0:03:38.09,0:03:41.04,Default,,0,0,0,,数个自然组合的小块
Dialogue: 0,0:03:42.76,0:03:43.82,Default,,0,0,0,,举例来说
Dialogue: 0,0:03:44.06,0:03:46.11,Default,,0,0,0,,我们想要构造一个随机数发生器
Dialogue: 0,0:03:46.22,0:03:49.40,Default,,0,0,0,,把该发生器的内部状态封装起来
Dialogue: 0,0:03:50.25,0:03:53.71,Default,,0,0,0,,这样我们就可以把选取随机数
Dialogue: 0,0:03:54.65,0:03:57.79,Default,,0,0,0,,和用于估计的蒙特卡洛方法分离开来
Dialogue: 0,0:03:58.65,0:04:01.52,Default,,0,0,0,,进一步地把它同由 Ceraso 发明的
Dialogue: 0,0:04:01.90,0:04:05.74,Default,,0,0,0,,求取 π 的公式分离开
Dialogue: 0,0:04:06.80,0:04:07.92,Default,,0,0,0,,相似地
Dialogue: 0,0:04:09.61,0:04:11.74,Default,,0,0,0,,当我们着手构建事物的模型时
Dialogue: 0,0:04:12.35,0:04:16.01,Default,,0,0,0,,我们去构建现实世界中事物的模型
Dialogue: 0,0:04:17.31,0:04:19.42,Default,,0,0,0,,我们想把程序组织成许多自然部分
Dialogue: 0,0:04:19.44,0:04:20.52,Default,,0,0,0,,这些部分就是
Dialogue: 0,0:04:21.05,0:04:23.16,Default,,0,0,0,,现实事物的镜像
Dialogue: 0,0:04:24.90,0:04:27.56,Default,,0,0,0,,举个例子 对于一个数字电路
Dialogue: 0,0:04:28.36,0:04:29.18,Default,,0,0,0,,我们会说
Dialogue: 0,0:04:30.44,0:04:31.44,Default,,0,0,0,,这儿有一个电路
Dialogue: 0,0:04:32.08,0:04:35.16,Default,,0,0,0,,它有一个这样的元件 有一个那样的元件
Dialogue: 0,0:04:40.10,0:04:43.58,Default,,0,0,0,,这些元件都有不同的“身份”
Dialogue: 0,0:04:43.58,0:04:44.59,Default,,0,0,0,,它们都有各自的状态
Dialogue: 0,0:04:45.55,0:04:47.13,Default,,0,0,0,,状态附着在电路上
Dialogue: 0,0:04:48.58,0:04:50.22,Default,,0,0,0,,我们认为这个元件是一个对象
Dialogue: 0,0:04:50.49,0:04:51.93,Default,,0,0,0,,这个元件又是另外一个不同的对象
Dialogue: 0,0:04:52.54,0:04:53.85,Default,,0,0,0,,当我们观察到系统发生了变化
Dialogue: 0,0:04:53.87,0:04:55.40,Default,,0,0,0,,信号从这里传递过来
Dialogue: 0,0:04:55.63,0:04:58.41,Default,,0,0,0,,改变了可能存放在这里的状态 并向这里继续传播
Dialogue: 0,0:04:58.67,0:05:00.75,Default,,0,0,0,,和一个存储在这里的状态交互
Dialogue: 0,0:05:01.24,0:05:02.17,Default,,0,0,0,,依此类推
Dialogue: 0,0:05:06.86,0:05:11.24,Default,,0,0,0,,我们想要在计算机中
Dialogue: 0,0:05:12.76,0:05:14.36,Default,,0,0,0,,构建模块化的系统
Dialogue: 0,0:05:14.68,0:05:17.87,Default,,0,0,0,,来反映我们对现实的看法
Dialogue: 0,0:05:17.88,0:05:19.87,Default,,0,0,0,,根据我们正在建模的实际系统
Dialogue: 0,0:05:19.88,0:05:20.91,Default,,0,0,0,,来划分子系统
Dialogue: 0,0:05:23.20,0:05:23.48,Default,,0,0,0,,然而
Dialogue: 0,0:05:25.74,0:05:28.99,Default,,0,0,0,,构建像这样的系统
Dialogue: 0,0:05:28.99,0:05:31.50,Default,,0,0,0,,看起来带来了不少技术上的麻烦
Dialogue: 0,0:05:31.52,0:05:32.75,Default,,0,0,0,,但这不是计算机造成的
Dialogue: 0,0:05:33.61,0:05:35.60,Default,,0,0,0,,或许 真正拖累我们
Dialogue: 0,0:05:36.70,0:05:38.65,Default,,0,0,0,,让我们花了那么大的功夫
Dialogue: 0,0:05:38.67,0:05:40.94,Default,,0,0,0,,才让程序反映现实世界的原因
Dialogue: 0,0:05:41.52,0:05:43.13,Default,,0,0,0,,是我们对现实世界的认识出了错
Dialogue: 0,0:05:44.55,0:05:46.75,Default,,0,0,0,,或许时间只是幻觉
Dialogue: 0,0:05:47.26,0:05:48.60,Default,,0,0,0,,什么都没有改变
Dialogue: 0,0:05:50.15,0:05:51.71,Default,,0,0,0,,就拿这个粉笔来说
Dialogue: 0,0:05:52.44,0:05:53.77,Default,,0,0,0,,我们认为它是一个对象
Dialogue: 0,0:05:54.01,0:05:54.99,Default,,0,0,0,,它有自己的状态
Dialogue: 0,0:05:55.82,0:05:59.29,Default,,0,0,0,,每时每刻 它都有一个位置和速度
Dialogue: 0,0:05:59.71,0:06:01.48,Default,,0,0,0,,如果我们做点什么 就可以改变它的状态
Dialogue: 0,0:06:04.34,0:06:07.37,Default,,0,0,0,,但是你如果了解一点相对性的概念
Dialogue: 0,0:06:07.74,0:06:09.71,Default,,0,0,0,,你可能会认为粉笔的路径
Dialogue: 0,0:06:09.72,0:06:11.34,Default,,0,0,0,,不是许多瞬时的离散点
Dialogue: 0,0:06:11.34,0:06:14.38,Default,,0,0,0,,一种深刻的见解是把整个粉笔的存在看作
Dialogue: 0,0:06:14.41,0:06:15.64,Default,,0,0,0,,时空中的路径
Dialogue: 0,0:06:16.02,0:06:17.37,Default,,0,0,0,,全部都展开了
Dialogue: 0,0:06:17.87,0:06:19.84,Default,,0,0,0,,没有单独的位置与速度
Dialogue: 0,0:06:19.84,0:06:23.80,Default,,0,0,0,,在时空中的存在是不会发生改变的
Dialogue: 0,0:06:24.64,0:06:26.51,Default,,0,0,0,,相似地 如果我们来考察这个电气系统
Dialogue: 0,0:06:27.69,0:06:30.43,Default,,0,0,0,,我们假设这个系统实现的是
Dialogue: 0,0:06:30.59,0:06:33.96,Default,,0,0,0,,某种信号处理系统
Dialogue: 0,0:06:34.36,0:06:36.68,Default,,0,0,0,,把这些元件组合在一起的工程师
Dialogue: 0,0:06:36.75,0:06:38.60,Default,,0,0,0,,也不会把它们看作
Dialogue: 0,0:06:38.96,0:06:41.40,Default,,0,0,0,,电压施加于每个独立的元件
Dialogue: 0,0:06:41.49,0:06:43.16,Default,,0,0,0,,转换成了某种东西
Dialogue: 0,0:06:43.34,0:06:45.52,Default,,0,0,0,,影响了这里的状态
Dialogue: 0,0:06:45.53,0:06:46.81,Default,,0,0,0,,还改变了那里的状态
Dialogue: 0,0:06:46.81,0:06:50.11,Default,,0,0,0,,没有一个做信号处理的会这样想
Dialogue: 0,0:06:50.42,0:06:51.84,Default,,0,0,0,,相反 你会说
Dialogue: 0,0:06:54.04,0:06:58.06,Default,,0,0,0,,这里有一个在时间上伸展的信号
Dialogue: 0,0:06:58.06,0:06:59.48,Default,,0,0,0,,如果把这个看作一个滤波器
Dialogue: 0,0:07:00.20,0:07:04.04,Default,,0,0,0,,这个滤波器会把整个信号转化成
Dialogue: 0,0:07:04.28,0:07:07.04,Default,,0,0,0,,不同的输出信号
Dialogue: 0,0:07:09.57,0:07:11.28,Default,,0,0,0,,你们不要把这些东西的状态
Dialogue: 0,0:07:11.28,0:07:13.29,Default,,0,0,0,,想象成在许多瞬间接连发生
Dialogue: 0,0:07:14.16,0:07:17.32,Default,,0,0,0,,我们把这个盒子看作一个整体
Dialogue: 0,0:07:17.32,0:07:20.16,Default,,0,0,0,,而不是在一个特定的瞬间
Dialogue: 0,0:07:20.40,0:07:21.96,Default,,0,0,0,,互相发送状态信息的小系统
Dialogue: 0,0:07:28.25,0:07:29.36,Default,,0,0,0,,今天我们将介绍
Dialogue: 0,0:07:29.39,0:07:31.13,Default,,0,0,0,,另一种分解系统的方法
Dialogue: 0,0:07:31.36,0:07:35.45,Default,,0,0,0,,站在信号工程师的角度去看待现实世界
Dialogue: 0,0:07:35.69,0:07:38.96,Default,,0,0,0,,而不再认为对象间通过消息传递来通信
Dialogue: 0,0:07:41.13,0:07:43.74,Default,,0,0,0,,它被称为“流处理”
Dialogue: 0,0:07:54.57,0:07:58.96,Default,,0,0,0,,我们打算展示
Dialogue: 0,0:08:00.59,0:08:04.16,Default,,0,0,0,,如何让我们的程序变得更加统一
Dialogue: 0,0:08:05.15,0:08:06.54,Default,,0,0,0,,从中看到更多的共性
Dialogue: 0,0:08:06.65,0:08:09.88,Default,,0,0,0,,如果我们跳出这些程序
Dialogue: 0,0:08:10.81,0:08:12.30,Default,,0,0,0,,我们会发现
Dialogue: 0,0:08:12.35,0:08:15.12,Default,,0,0,0,,我们对时序的考虑过度了
Dialogue: 0,0:08:16.89,0:08:20.22,Default,,0,0,0,,我们先来对比两个过程
Dialogue: 0,0:08:23.55,0:08:25.69,Default,,0,0,0,,第一个是这样
Dialogue: 0,0:08:25.69,0:08:27.77,Default,,0,0,0,,想像这有一个树
Dialogue: 0,0:08:30.40,0:08:32.14,Default,,0,0,0,,一个由整数构成的树
Dialogue: 0,0:08:33.28,0:08:34.42,Default,,0,0,0,,一个二叉树
Dialogue: 0,0:08:36.12,0:08:36.97,Default,,0,0,0,,这里是1
Dialogue: 0,0:08:39.10,0:08:40.23,Default,,0,0,0,,看起来就像这样
Dialogue: 0,0:08:40.23,0:08:42.92,Default,,0,0,0,,在每个节点上都有一个整数
Dialogue: 0,0:08:45.18,0:08:47.80,Default,,0,0,0,,我们想计算
Dialogue: 0,0:08:48.67,0:08:51.56,Default,,0,0,0,,对这个树中所有的奇数
Dialogue: 0,0:08:52.30,0:08:55.10,Default,,0,0,0,,计算它们的平方和
Dialogue: 0,0:08:57.05,0:08:59.48,Default,,0,0,0,,我们对这类问题很熟悉
Dialogue: 0,0:08:59.48,0:09:01.95,Default,,0,0,0,,有一种递归策略求解它
Dialogue: 0,0:09:02.93,0:09:04.35,Default,,0,0,0,,观察每个叶子节点
Dialogue: 0,0:09:04.56,0:09:06.68,Default,,0,0,0,,如果是奇数我们就求它的平方 并加和
Dialogue: 0,0:09:06.70,0:09:07.77,Default,,0,0,0,,如果是偶数 就是0
Dialogue: 0,0:09:08.68,0:09:12.11,Default,,0,0,0,,递归地看 对于每一颗树 我们可以说
Dialogue: 0,0:09:12.65,0:09:13.84,Default,,0,0,0,,它的平方和等于
Dialogue: 0,0:09:13.92,0:09:15.93,Default,,0,0,0,,右子树的平方和 加上左子树的平方和
Dialogue: 0,0:09:16.25,0:09:17.64,Default,,0,0,0,,就这样沿着节点递归下去
Dialogue: 0,0:09:17.64,0:09:18.70,Default,,0,0,0,,我们已经很熟悉
Dialogue: 0,0:09:19.26,0:09:20.36,Default,,0,0,0,,这种程序设计的思考方式了
Dialogue: 0,0:09:20.36,0:09:22.59,Default,,0,0,0,,我们来幻灯片上看一下
Dialogue: 0,0:09:23.82,0:09:26.75,Default,,0,0,0,,为了计算一棵树中奇数的平方和
Dialogue: 0,0:09:27.37,0:09:29.36,Default,,0,0,0,,我们先要判断它是否是一个叶子节点
Dialogue: 0,0:09:29.82,0:09:31.95,Default,,0,0,0,,判断方法则是考察该节点是否为整数
Dialogue: 0,0:09:32.88,0:09:36.38,Default,,0,0,0,,继而判断其奇偶性 以及是否应该求取平方并加和
Dialogue: 0,0:09:37.16,0:09:38.99,Default,,0,0,0,,然后 整个的解就是
Dialogue: 0,0:09:39.21,0:09:42.12,Default,,0,0,0,,左、右子树解的总和
Dialogue: 0,0:09:46.34,0:09:50.56,Default,,0,0,0,,好的 让我们再来和下面一个问题对比一下
Dialogue: 0,0:09:51.56,0:09:53.68,Default,,0,0,0,,假如给你一个整数N
Dialogue: 0,0:09:54.73,0:09:57.88,Default,,0,0,0,,再给定一个函数 把它应用在
Dialogue: 0,0:09:57.93,0:09:58.83,Default,,0,0,0,,1到N的每一个数上
Dialogue: 0,0:09:59.10,0:10:01.08,Default,,0,0,0,,我想把其中的一些值收集成一个表
Dialogue: 0,0:10:01.28,0:10:04.65,Default,,0,0,0,,那些满足某种属性的函数值
Dialogue: 0,0:10:05.60,0:10:06.88,Default,,0,0,0,,这是种一般性的说法
Dialogue: 0,0:10:06.88,0:10:07.98,Default,,0,0,0,,说得更具体一点
Dialogue: 0,0:10:08.62,0:10:10.48,Default,,0,0,0,,假设对于每个整数K
Dialogue: 0,0:10:10.65,0:10:12.51,Default,,0,0,0,,计算第K个斐波那契数
Dialogue: 0,0:10:14.21,0:10:16.27,Default,,0,0,0,,然后挑出其中的奇数
Dialogue: 0,0:10:16.83,0:10:18.40,Default,,0,0,0,,并把它们组成一个表
Dialogue: 0,0:10:19.05,0:10:20.71,Default,,0,0,0,,这个过程是这样的
Dialogue: 0,0:10:23.73,0:10:26.24,Default,,0,0,0,,寻找前N个斐波那契数中的奇数
Dialogue: 0,0:10:26.24,0:10:28.91,Default,,0,0,0,,这里是我们一直以来采用的循环方法
Dialogue: 0,0:10:28.91,0:10:29.82,Default,,0,0,0,,用到了递归
Dialogue: 0,0:10:30.80,0:10:31.79,Default,,0,0,0,,以K为循环变量
Dialogue: 0,0:10:32.03,0:10:34.35,Default,,0,0,0,,如果K大于N 返回空表
Dialogue: 0,0:10:35.13,0:10:37.36,Default,,0,0,0,,否则计算第K个斐波那契数
Dialogue: 0,0:10:37.44,0:10:38.06,Default,,0,0,0,,将其与变量F绑定
Dialogue: 0,0:10:40.37,0:10:42.84,Default,,0,0,0,,如果是奇数 我们把它与
Dialogue: 0,0:10:43.76,0:10:46.01,Default,,0,0,0,,从K+1计算得到的表相连接
Dialogue: 0,0:10:47.69,0:10:50.12,Default,,0,0,0,,否则 我们只取从K+1计算得到的结果
Dialogue: 0,0:10:50.73,0:10:53.00,Default,,0,0,0,,这是迭代式循环的标准写法
Dialogue: 0,0:10:53.00,0:10:55.56,Default,,0,0,0,,我们以1为初值 启动这个循环
Dialogue: 0,0:10:57.58,0:11:00.06,Default,,0,0,0,,好的 就是这两个过程
Dialogue: 0,0:11:01.60,0:11:02.90,Default,,0,0,0,,它们看起来非常不同
Dialogue: 0,0:11:02.90,0:11:04.20,Default,,0,0,0,,完全不同的结构
Dialogue: 0,0:11:04.25,0:11:06.89,Default,,0,0,0,,然而 从一个特定的角度来看
Dialogue: 0,0:11:06.92,0:11:09.61,Default,,0,0,0,,两个过程做的事情是一样的
Dialogue: 0,0:11:11.33,0:11:14.67,Default,,0,0,0,,如果我是一个信号处理工程师
Dialogue: 0,0:11:14.70,0:11:16.81,Default,,0,0,0,,我可能会说
Dialogue: 0,0:11:18.24,0:11:26.76,Default,,0,0,0,,第一个过程枚举了树的叶节点
Dialogue: 0,0:11:31.16,0:11:34.56,Default,,0,0,0,,可以认为是信号从一个全是叶节点的地方输出
Dialogue: 0,0:11:35.33,0:11:43.39,Default,,0,0,0,,我们想要过滤出其中的奇数
Dialogue: 0,0:11:43.58,0:11:44.94,Default,,0,0,0,,把它们放入某种滤波器中
Dialogue: 0,0:11:45.19,0:11:47.79,Default,,0,0,0,,然后再把它们放入某种换能器
Dialogue: 0,0:11:49.20,0:11:51.69,Default,,0,0,0,,对每一个输出 我们对其取平方
Dialogue: 0,0:11:54.44,0:11:57.44,Default,,0,0,0,,最后把结果累积在一起
Dialogue: 0,0:11:58.29,0:12:00.04,Default,,0,0,0,,我们以0为初值
Dialogue: 0,0:12:00.35,0:12:03.37,Default,,0,0,0,,通过加法把它们累积起来
Dialogue: 0,0:12:07.14,0:12:08.21,Default,,0,0,0,,这是第一个程序
Dialogue: 0,0:12:08.21,0:12:09.18,Default,,0,0,0,,对于第二个程序
Dialogue: 0,0:12:09.24,0:12:11.21,Default,,0,0,0,,我也可以用一种非常类似的方法来描述
Dialogue: 0,0:12:11.78,0:12:13.42,Default,,0,0,0,,我们枚举
Dialogue: 0,0:12:15.80,0:12:19.10,Default,,0,0,0,,从1到N这个区间上的数
Dialogue: 0,0:12:22.50,0:12:24.40,Default,,0,0,0,,对于每个数
Dialogue: 0,0:12:25.45,0:12:26.92,Default,,0,0,0,,计算对应的斐波那契数
Dialogue: 0,0:12:27.79,0:12:29.27,Default,,0,0,0,,再放入一个换能器
Dialogue: 0,0:12:29.27,0:12:30.78,Default,,0,0,0,,对于输出的结果
Dialogue: 0,0:12:31.31,0:12:34.20,Default,,0,0,0,,再通过奇偶性进行过滤
Dialogue: 0,0:12:36.27,0:12:39.24,Default,,0,0,0,,最后 我们将这些放入累积函数
Dialogue: 0,0:12:39.35,0:12:40.56,Default,,0,0,0,,这次我们要累积出一个表
Dialogue: 0,0:12:40.78,0:12:42.17,Default,,0,0,0,,所以我们用CONS来做积累
Dialogue: 0,0:12:42.59,0:12:43.77,Default,,0,0,0,,以空表为初始值
Dialogue: 0,0:12:47.11,0:12:49.80,Default,,0,0,0,,从这个角度来看
Dialogue: 0,0:12:49.85,0:12:51.84,Default,,0,0,0,,这两个程序真的是太相似了
Dialogue: 0,0:12:51.90,0:12:52.84,Default,,0,0,0,,问题在于
Dialogue: 0,0:12:53.20,0:12:56.49,Default,,0,0,0,,两个程序的写法导致
Dialogue: 0,0:12:56.64,0:12:58.05,Default,,0,0,0,,我们看不出其中的共性
Dialogue: 0,0:12:58.05,0:13:01.44,Default,,0,0,0,,再回头来看奇数平方和的问题
Dialogue: 0,0:13:02.22,0:13:04.64,Default,,0,0,0,,问题来了 哪个是枚举函数呢?
Dialogue: 0,0:13:06.35,0:13:08.14,Default,,0,0,0,,程序中哪一部分有枚举的作用?
Dialogue: 0,0:13:08.14,0:13:10.52,Default,,0,0,0,,枚举不是仅仅在一个地方表现出来的
Dialogue: 0,0:13:11.02,0:13:15.47,Default,,0,0,0,,在叶子节点的判断处存在一部分
Dialogue: 0,0:13:16.43,0:13:17.16,Default,,0,0,0,,在这个判断循环终止的地方
Dialogue: 0,0:13:17.16,0:13:20.06,Default,,0,0,0,,也下面的递归结构中也有体现
Dialogue: 0,0:13:23.15,0:13:24.12,Default,,0,0,0,,累积函数又在哪儿呢?
Dialogue: 0,0:13:24.12,0:13:25.68,Default,,0,0,0,,它也不只在一个地方
Dialogue: 0,0:13:25.68,0:13:30.73,Default,,0,0,0,,它在 0 和 + 这两个地方分别体现出来
Dialogue: 0,0:13:32.00,0:13:34.51,Default,,0,0,0,,累积函数分散在过程的每个部分
Dialogue: 0,0:13:34.51,0:13:39.05,Default,,0,0,0,,相似地 我们来观察奇数斐波那契数的例子
Dialogue: 0,0:13:39.05,0:13:42.80,Default,,0,0,0,,某种意义上 程序中也存在枚举函数与累积函数
Dialogue: 0,0:13:42.80,0:13:44.01,Default,,0,0,0,,但看起来非常不同
Dialogue: 0,0:13:44.62,0:13:50.09,Default,,0,0,0,,枚举部分地表现在(> k n)的判断中
Dialogue: 0,0:13:50.38,0:13:52.84,Default,,0,0,0,,部分地表现在下面的递归调用中
Dialogue: 0,0:13:53.18,0:13:54.24,Default,,0,0,0,,还有就是启动循环的地方
Dialogue: 0,0:13:55.68,0:13:56.32,Default,,0,0,0,,同样地
Dialogue: 0,0:13:56.52,0:13:58.76,Default,,0,0,0,,其中也混杂了累积函数
Dialogue: 0,0:13:58.91,0:14:00.12,Default,,0,0,0,,分别在这里
Dialogue: 0,0:14:00.41,0:14:01.40,Default,,0,0,0,,和这里
Dialogue: 0,0:14:03.60,0:14:06.08,Default,,0,0,0,,所以这些非常自然的部分
Dialogue: 0,0:14:08.73,0:14:12.65,Default,,0,0,0,,我们之前画的那些方框在程序中完全看不出来
Dialogue: 0,0:14:13.26,0:14:14.36,Default,,0,0,0,,因为它们混杂在一起了
Dialogue: 0,0:14:14.36,0:14:16.29,Default,,0,0,0,,这些程序并没有很好地对问题进行切分
Dialogue: 0,0:14:19.45,0:14:22.17,Default,,0,0,0,,回到计算机科学的基本原理上来
Dialogue: 0,0:14:22.19,0:14:23.63,Default,,0,0,0,,为了控制某种东西
Dialogue: 0,0:14:23.63,0:14:24.96,Default,,0,0,0,,你需要它的名字
Dialogue: 0,0:14:25.80,0:14:28.44,Default,,0,0,0,,我们还没有很好地掌握按这种方式来思考
Dialogue: 0,0:14:28.67,0:14:31.06,Default,,0,0,0,,这是因为我们没有显式地操作它们的手段
Dialogue: 0,0:14:31.06,0:14:33.80,Default,,0,0,0,,我们没有一门好的语言来讨论它们
Dialogue: 0,0:14:35.42,0:14:38.86,Default,,0,0,0,,好吧 我们来创造一门合适的语言
Dialogue: 0,0:14:42.52,0:14:44.04,Default,,0,0,0,,用它来构建这些器件
Dialogue: 0,0:14:44.78,0:14:47.21,Default,,0,0,0,,这种语言的关键在于
Dialogue: 0,0:14:47.21,0:14:49.71,Default,,0,0,0,,这些叫作信号的东西到底是什么?
Dialogue: 0,0:14:50.48,0:14:53.32,Default,,0,0,0,,这些沿着箭头传递的是什么?
Dialogue: 0,0:14:56.88,0:14:57.71,Default,,0,0,0,,这些东西
Dialogue: 0,0:14:59.85,0:15:03.52,Default,,0,0,0,,是一种称作“流”的数据结构
Dialogue: 0,0:15:03.79,0:15:05.87,Default,,0,0,0,,这也是发明这门语言的关键
Dialogue: 0,0:15:07.98,0:15:08.51,Default,,0,0,0,,“流”是什么东西呢?
Dialogue: 0,0:15:08.52,0:15:11.50,Default,,0,0,0,,和其它的东西一样 “流”是一种数据抽象
Dialogue: 0,0:15:12.22,0:15:15.82,Default,,0,0,0,,所以 我先说明它的选择函数与构造函数分别是什么
Dialogue: 0,0:15:16.87,0:15:19.48,Default,,0,0,0,,对于流结构 我们有一个构造函数
Dialogue: 0,0:15:19.98,0:15:21.43,Default,,0,0,0,,我们称其为CONS-STREAM
Dialogue: 0,0:15:25.69,0:15:28.11,Default,,0,0,0,,CONS-STREAM把两个事物放在一起
Dialogue: 0,0:15:28.59,0:15:30.22,Default,,0,0,0,,构造出一个流
Dialogue: 0,0:15:32.04,0:15:33.85,Default,,0,0,0,,选择函数叫作HEAD
Dialogue: 0,0:15:33.98,0:15:36.11,Default,,0,0,0,,用于从流中提取数据
Dialogue: 0,0:15:38.01,0:15:38.86,Default,,0,0,0,,如果我有一个流
Dialogue: 0,0:15:39.00,0:15:40.41,Default,,0,0,0,,我可以取它的头部
Dialogue: 0,0:15:41.13,0:15:42.38,Default,,0,0,0,,也可以取它的尾部
Dialogue: 0,0:15:44.72,0:15:47.42,Default,,0,0,0,,我把和George的约定告诉你
Dialogue: 0,0:15:48.24,0:15:52.70,Default,,0,0,0,,让你们知道和这个相关的公理
Dialogue: 0,0:15:53.44,0:16:00.17,Default,,0,0,0,,对于任何的X与Y
Dialogue: 0,0:16:03.40,0:16:05.44,Default,,0,0,0,,如果我把它们构造成一个流 并取其头部
Dialogue: 0,0:16:05.69,0:16:11.96,Default,,0,0,0,,(HEAD (CONS-STREAM X Y))
Dialogue: 0,0:16:13.29,0:16:14.52,Default,,0,0,0,,结果就是X
Dialogue: 0,0:16:16.14,0:16:27.45,Default,,0,0,0,,(TAIL (CONS-STREAM X Y)) = Y
Dialogue: 0,0:16:28.44,0:16:34.75,Default,,0,0,0,,一个构造函数 两个选择函数 一个公理 就是这些
Dialogue: 0,0:16:34.75,0:16:35.85,Default,,0,0,0,,这里有点可疑
Dialogue: 0,0:16:36.98,0:16:39.00,Default,,0,0,0,,你可能注意到了
Dialogue: 0,0:16:40.19,0:16:42.08,Default,,0,0,0,,这些就是CONS、CAR和CDR的公理
Dialogue: 0,0:16:43.63,0:16:46.56,Default,,0,0,0,,把CONS-STREAM换成CONS
Dialogue: 0,0:16:47.10,0:16:49.80,Default,,0,0,0,,HEAD换成CAR TAIL换成CDR
Dialogue: 0,0:16:50.76,0:16:52.81,Default,,0,0,0,,这些就是序对的公理
Dialogue: 0,0:16:52.81,0:16:54.32,Default,,0,0,0,,事实上 还有另一个东西
Dialogue: 0,0:16:55.13,0:16:56.80,Default,,0,0,0,,我们有一个叫THE-EMPTY-STREAM(空流)的东西
Dialogue: 0,0:17:02.80,0:17:04.04,Default,,0,0,0,,像空表一样
Dialogue: 0,0:17:08.31,0:17:10.03,Default,,0,0,0,,为什么我要引入这个术语呢?
Dialogue: 0,0:17:10.03,0:17:12.12,Default,,0,0,0,,为什么我不继续使用序对与表呢?
Dialogue: 0,0:17:12.78,0:17:13.79,Default,,0,0,0,,后面我们就知道了
Dialogue: 0,0:17:15.51,0:17:18.24,Default,,0,0,0,,暂时地 你们可以把术语“流”
Dialogue: 0,0:17:18.30,0:17:21.56,Default,,0,0,0,,当作“表”的另一种说法
Dialogue: 0,0:17:21.56,0:17:22.99,Default,,0,0,0,,一会儿我们就会知道 为什么
Dialogue: 0,0:17:23.61,0:17:26.09,Default,,0,0,0,,为什么我们需要这个额外的抽象层
Dialogue: 0,0:17:26.83,0:17:28.15,Default,,0,0,0,,而不是继续把它看做表
Dialogue: 0,0:17:32.30,0:17:33.72,Default,,0,0,0,,好的 有了流之后
Dialogue: 0,0:17:33.74,0:17:35.85,Default,,0,0,0,,我们就开始构建语言的部件了
Dialogue: 0,0:17:37.04,0:17:38.17,Default,,0,0,0,,用它来操作流
Dialogue: 0,0:17:38.75,0:17:42.12,Default,,0,0,0,,我们可以构建出太多有用的东西了
Dialogue: 0,0:17:42.12,0:17:42.81,Default,,0,0,0,,举例来说
Dialogue: 0,0:17:44.89,0:17:49.79,Default,,0,0,0,,我们构建MAP-STREAM 它的一个参数是流S
Dialogue: 0,0:17:54.80,0:17:56.62,Default,,0,0,0,,以及一个过程
Dialogue: 0,0:17:57.80,0:17:59.21,Default,,0,0,0,,它会生成一个新的流
Dialogue: 0,0:18:00.14,0:18:02.28,Default,,0,0,0,,它的构成元素是
Dialogue: 0,0:18:02.28,0:18:04.88,Default,,0,0,0,,将PROC应用到S的后续元素得到的结果
Dialogue: 0,0:18:05.87,0:18:07.40,Default,,0,0,0,,我们以前见过类似的
Dialogue: 0,0:18:07.40,0:18:10.24,Default,,0,0,0,,就是以前在表上定义的MAP过程
Dialogue: 0,0:18:10.95,0:18:12.60,Default,,0,0,0,,除了判断EMPTY-STREAM的部分
Dialogue: 0,0:18:12.60,0:18:14.65,Default,,0,0,0,,完全就和MAP一样
Dialogue: 0,0:18:14.65,0:18:15.56,Default,,0,0,0,,哦 我忘了说了
Dialogue: 0,0:18:15.56,0:18:17.15,Default,,0,0,0,,EMPTY-STREAM?就和NULL?差不多
Dialogue: 0,0:18:18.03,0:18:20.48,Default,,0,0,0,,如果是空的 就返回一个空的流
Dialogue: 0,0:18:20.51,0:18:22.28,Default,,0,0,0,,否则 就生成一个新的流
Dialogue: 0,0:18:23.52,0:18:27.18,Default,,0,0,0,,其第一个元素是PROC应用在流头部的结果
Dialogue: 0,0:18:28.51,0:18:29.32,Default,,0,0,0,,剩下的是
Dialogue: 0,0:18:29.60,0:18:32.43,Default,,0,0,0,,是MAP-STREAM对流尾部应用的结果
Dialogue: 0,0:18:33.14,0:18:35.90,Default,,0,0,0,,太像我们之前讲的MAP了
Dialogue: 0,0:18:37.03,0:18:38.20,Default,,0,0,0,,还有一个有用的函数
Dialogue: 0,0:18:38.35,0:18:40.46,Default,,0,0,0,,过滤函数 就是那个用来过滤的盒子
Dialogue: 0,0:18:40.46,0:18:43.89,Default,,0,0,0,,以一个谓词和一个流作为参数
Dialogue: 0,0:18:43.89,0:18:45.08,Default,,0,0,0,,它将生成一个新的流
Dialogue: 0,0:18:45.80,0:18:48.17,Default,,0,0,0,,包含了在流S中所有
Dialogue: 0,0:18:48.33,0:18:49.48,Default,,0,0,0,,满足谓词PRED的元素
Dialogue: 0,0:18:50.38,0:18:51.31,Default,,0,0,0,,这是一个“按条件分析语句”
Dialogue: 0,0:18:51.32,0:18:52.73,Default,,0,0,0,,如果流是空的
Dialogue: 0,0:18:53.04,0:18:54.22,Default,,0,0,0,,就返回一个空流
Dialogue: 0,0:18:56.28,0:18:59.18,Default,,0,0,0,,这里 用谓词来判断流的头元素
Dialogue: 0,0:19:00.06,0:19:01.04,Default,,0,0,0,,如果为真
Dialogue: 0,0:19:01.53,0:19:02.83,Default,,0,0,0,,就把这个元素
Dialogue: 0,0:19:03.02,0:19:06.22,Default,,0,0,0,,和过滤流的尾元素得到的结果连接在一起
Dialogue: 0,0:19:08.22,0:19:10.04,Default,,0,0,0,,否则 如果谓词判断为假
Dialogue: 0,0:19:10.49,0:19:11.98,Default,,0,0,0,,就只返回过滤流的尾元素的结果
Dialogue: 0,0:19:13.50,0:19:14.46,Default,,0,0,0,,这就是过滤函数的原理
Dialogue: 0,0:19:16.59,0:19:18.56,Default,,0,0,0,,剩下的我快速过一遍
Dialogue: 0,0:19:18.56,0:19:20.70,Default,,0,0,0,,这些在书上都有 你们可以自己看
Dialogue: 0,0:19:20.88,0:19:21.80,Default,,0,0,0,,来马上过一遍
Dialogue: 0,0:19:22.11,0:19:22.94,Default,,0,0,0,,过程ACCUMULATE
Dialogue: 0,0:19:23.26,0:19:26.92,Default,,0,0,0,,ACCUMULATE的参数有:一个组合函数
Dialogue: 0,0:19:27.36,0:19:29.05,Default,,0,0,0,,一个初始值和一个流
Dialogue: 0,0:19:29.96,0:19:31.13,Default,,0,0,0,,将它们组合在一起
Dialogue: 0,0:19:31.56,0:19:33.69,Default,,0,0,0,,如果流为空 返回初始值
Dialogue: 0,0:19:33.97,0:19:36.20,Default,,0,0,0,,否则 我们就把流头部
Dialogue: 0,0:19:36.32,0:19:37.82,Default,,0,0,0,,和流尾部做ACCUMLATE的结果
Dialogue: 0,0:19:38.01,0:19:40.24,Default,,0,0,0,,组合起来
Dialogue: 0,0:19:40.90,0:19:42.83,Default,,0,0,0,,这就是把流中元素累积在一起的方法
Dialogue: 0,0:19:42.83,0:19:43.98,Default,,0,0,0,,我会用加法来累积
Dialogue: 0,0:19:45.83,0:19:47.56,Default,,0,0,0,,如何枚举树上的叶节点呢?
Dialogue: 0,0:19:48.06,0:19:52.89,Default,,0,0,0,,如果这个树只是一个叶节点
Dialogue: 0,0:19:53.79,0:19:55.90,Default,,0,0,0,,我就构造一个只含有一个叶子节点的流
Dialogue: 0,0:19:56.64,0:19:59.32,Default,,0,0,0,,否则的话 我就把
Dialogue: 0,0:19:59.61,0:20:02.35,Default,,0,0,0,,左、右子树枚举的结果合并起来
Dialogue: 0,0:20:04.34,0:20:08.32,Default,,0,0,0,,这里的APPEND-STREAM跟表上的APPEND类似
Dialogue: 0,0:20:13.19,0:20:13.85,Default,,0,0,0,,再来看这个
Dialogue: 0,0:20:13.85,0:20:17.53,Default,,0,0,0,,这跟和合并两个表的过程太相似了
Dialogue: 0,0:20:18.91,0:20:20.60,Default,,0,0,0,,如何枚举一个区间呢?
Dialogue: 0,0:20:21.96,0:20:23.77,Default,,0,0,0,,它有两个参数 LOW和HIGH
Dialogue: 0,0:20:23.88,0:20:27.00,Default,,0,0,0,,生成一个包含从LOW到HIGH的所有整数的流
Dialogue: 0,0:20:28.32,0:20:29.88,Default,,0,0,0,,由此 我们就可以构造一大堆的元件
Dialogue: 0,0:20:31.89,0:20:34.48,Default,,0,0,0,,这就是一门用来讨论流的小型语言
Dialogue: 0,0:20:34.49,0:20:35.32,Default,,0,0,0,,当我们有了流
Dialogue: 0,0:20:35.32,0:20:37.67,Default,,0,0,0,,就可以构建用于操作它们的过程
Dialogue: 0,0:20:37.67,0:20:39.04,Default,,0,0,0,,请注意 我们正在构建一门语言
Dialogue: 0,0:20:40.20,0:20:42.22,Default,,0,0,0,,现在 我们可以用这门语言来表达我们的想法
Dialogue: 0,0:20:43.06,0:20:47.31,Default,,0,0,0,,这个原始过程是累加树中奇数的平方的
Dialogue: 0,0:20:47.31,0:20:52.62,Default,,0,0,0,,现在你会发现 它和那些方块图如出一辙
Dialogue: 0,0:20:52.64,0:20:54.59,Default,,0,0,0,,跟我们的信号处理方块图相吻合
Dialogue: 0,0:20:54.59,0:20:57.53,Default,,0,0,0,,要计算树上奇数平方和
Dialogue: 0,0:20:58.06,0:21:00.80,Default,,0,0,0,,先枚举树上的叶子节点
Dialogue: 0,0:21:01.32,0:21:03.72,Default,,0,0,0,,过滤出奇数
Dialogue: 0,0:21:04.83,0:21:06.54,Default,,0,0,0,,再用平方来做映射
Dialogue: 0,0:21:09.32,0:21:13.34,Default,,0,0,0,,最后用加法来累积 初始值是0
Dialogue: 0,0:21:14.76,0:21:17.20,Default,,0,0,0,,这样我们就可以看到需要的片段
Dialogue: 0,0:21:17.29,0:21:19.36,Default,,0,0,0,,类似地 斐波那契数的那个问题
Dialogue: 0,0:21:20.04,0:21:21.88,Default,,0,0,0,,我们如何获得奇斐波那契数呢?
Dialogue: 0,0:21:22.05,0:21:24.57,Default,,0,0,0,,从1到N枚举整数
Dialogue: 0,0:21:26.32,0:21:28.64,Default,,0,0,0,,再把FIB过程映射到上面
Dialogue: 0,0:21:28.99,0:21:30.70,Default,,0,0,0,,用来求取每项斐波那契数
Dialogue: 0,0:21:30.92,0:21:33.79,Default,,0,0,0,,过滤出奇数的部分
Dialogue: 0,0:21:34.81,0:21:36.64,Default,,0,0,0,,最后 以空表为初始值
Dialogue: 0,0:21:36.88,0:21:39.12,Default,,0,0,0,,用CONS将它们积累起来
Dialogue: 0,0:21:43.65,0:21:47.53,Default,,0,0,0,,那么 这么做有什么优势呢?
Dialogue: 0,0:21:47.68,0:21:48.59,Default,,0,0,0,,首先一点
Dialogue: 0,0:21:48.68,0:21:51.15,Default,,0,0,0,,我们现在有可以用来混搭的元件了
Dialogue: 0,0:21:51.88,0:21:52.64,Default,,0,0,0,,比如说
Dialogue: 0,0:21:52.91,0:21:55.08,Default,,0,0,0,,如果我想把这里改变一下
Dialogue: 0,0:21:58.19,0:22:00.32,Default,,0,0,0,,想要计算整数的平方再进行过滤
Dialogue: 0,0:22:00.33,0:22:01.34,Default,,0,0,0,,我只需要
Dialogue: 0,0:22:01.90,0:22:03.64,Default,,0,0,0,,拿个像这里的MAP SQUARE这样的元件
Dialogue: 0,0:22:03.68,0:22:05.40,Default,,0,0,0,,放进去就行了
Dialogue: 0,0:22:06.57,0:22:07.60,Default,,0,0,0,,又或者 如果我们想
Dialogue: 0,0:22:07.69,0:22:11.45,Default,,0,0,0,,寻找树的叶节点对应的斐波那契数
Dialogue: 0,0:22:11.58,0:22:12.36,Default,,0,0,0,,而不是一个序列所对应的
Dialogue: 0,0:22:12.38,0:22:13.24,Default,,0,0,0,,我只需要
Dialogue: 0,0:22:13.40,0:22:15.93,Default,,0,0,0,,用这个枚举函数替换这个枚举函数
Dialogue: 0,0:22:18.03,0:22:19.82,Default,,0,0,0,,看到了吧 流处理的优势就是
Dialogue: 0,0:22:20.24,0:22:21.53,Default,,0,0,0,,我们建立了 --
Dialogue: 0,0:22:22.36,0:22:24.96,Default,,0,0,0,,这也是本课中的一个重要主题 --
Dialogue: 0,0:22:25.29,0:22:27.48,Default,,0,0,0,,我们建立了一个约定的接口
Dialogue: 0,0:22:32.89,0:22:37.15,Default,,0,0,0,,约定的接口可以让我们把事物粘合起来
Dialogue: 0,0:22:38.30,0:22:39.55,Default,,0,0,0,,像MAP和FILTER这样的东西
Dialogue: 0,0:22:39.79,0:22:41.64,Default,,0,0,0,,可以作为一组标准的组件
Dialogue: 0,0:22:41.68,0:22:44.76,Default,,0,0,0,,我们可以拿过来随意组合去构造程序
Dialogue: 0,0:22:45.75,0:22:48.81,Default,,0,0,0,,它让我们看到了程序的共性
Dialogue: 0,0:22:49.95,0:22:50.92,Default,,0,0,0,,虽然在这里
Dialogue: 0,0:22:51.08,0:22:53.07,Default,,0,0,0,,我只是给你们演示了两个过程而已
Dialogue: 0,0:22:53.86,0:22:55.16,Default,,0,0,0,,但是我要告诉你
Dialogue: 0,0:22:55.20,0:22:57.77,Default,,0,0,0,,像这种用MAP、FILTER和ACCUMULATE
Dialogue: 0,0:22:57.80,0:23:01.00,Default,,0,0,0,,组合起来构建程序的方式是非常非常通用的
Dialogue: 0,0:23:01.41,0:23:07.28,Default,,0,0,0,,这是一种“生成-测试”的编程范式
Dialogue: 0,0:23:07.77,0:23:09.10,Default,,0,0,0,,举例来看
Dialogue: 0,0:23:09.39,0:23:12.94,Default,,0,0,0,,Richarc Waters -- MIT的一名硕士生
Dialogue: 0,0:23:12.96,0:23:15.26,Default,,0,0,0,,他的学位论文的一部分调研了
Dialogue: 0,0:23:15.80,0:23:19.21,Default,,0,0,0,,IBM的科学计算程序库的主要代码
Dialogue: 0,0:23:19.82,0:23:23.31,Default,,0,0,0,,发现其中60%的程序
Dialogue: 0,0:23:24.06,0:23:28.25,Default,,0,0,0,,都可以用这样的范式来准确的表示出来
Dialogue: 0,0:23:28.86,0:23:30.17,Default,,0,0,0,,只用MAP、FILTER和ACCUMULATE
Dialogue: 0,0:23:30.57,0:23:31.50,Default,,0,0,0,,好 让我们休息一会
Dialogue: 0,0:23:36.59,0:23:37.12,Default,,0,0,0,,有问题吗?
Dialogue: 0,0:23:41.18,0:23:42.89,Default,,0,0,0,,学生:整件事情的本质好像只是
Dialogue: 0,0:23:42.89,0:23:45.96,Default,,0,0,0,,因为你用了一个统一、简单的数据结构
Dialogue: 0,0:23:46.25,0:23:47.66,Default,,0,0,0,,也就是流
Dialogue: 0,0:23:48.38,0:23:48.92,Default,,0,0,0,,教授:对
Dialogue: 0,0:23:48.92,0:23:50.38,Default,,0,0,0,,本质就是
Dialogue: 0,0:23:50.40,0:23:53.07,Default,,0,0,0,,用这种约定的接口
Dialogue: 0,0:23:53.71,0:23:55.61,Default,,0,0,0,,因此你可以把许多东西组合起来
Dialogue: 0,0:23:56.01,0:23:58.78,Default,,0,0,0,,流只是 就像你说的
Dialogue: 0,0:23:58.78,0:24:00.89,Default,,0,0,0,,只是一种可以支持那样操作的统一的数据结构而已
Dialogue: 0,0:24:00.89,0:24:02.84,Default,,0,0,0,,顺便说下 这非常像APL
Dialogue: 0,0:24:03.60,0:24:05.21,Default,,0,0,0,,APL有着非常相似的思想
Dialogue: 0,0:24:05.21,0:24:06.96,Default,,0,0,0,,只是在APL中使用的不是流
Dialogue: 0,0:24:07.13,0:24:08.44,Default,,0,0,0,,而是使用数组和向量
Dialogue: 0,0:24:09.56,0:24:14.48,Default,,0,0,0,,而且APL的威力就在于此
Dialogue: 0,0:24:19.91,0:24:20.91,Default,,0,0,0,,好吧 谢谢
Dialogue: 0,0:24:20.91,0:24:21.66,Default,,0,0,0,,休息一下
Dialogue: 0,0:24:21.66,0:24:30.35,Default,,0,0,0,,[音乐]
Dialogue: 0,0:24:30.44,0:24:35.77,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》
Dialogue: 0,0:24:41.00,0:24:45.39,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授
Dialogue: 0,0:24:45.42,0:24:47.96,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》
Dialogue: 0,0:24:47.98,0:24:52.70,Declare,,0,0,0,,{\an2\fad(500,500)}流 I
Dialogue: 0,0:24:57.47,0:24:57.61,Default,,0,0,0,,好的
Dialogue: 0,0:24:57.61,0:24:58.59,Default,,0,0,0,,我们已经见识过了
Dialogue: 0,0:25:00.54,0:25:03.20,Default,,0,0,0,,如何用流来组织计算过程
Dialogue: 0,0:25:03.85,0:25:05.47,Default,,0,0,0,,但是现在我想要给你们再演示两个
Dialogue: 0,0:25:05.93,0:25:09.12,Default,,0,0,0,,更复杂的例子
Dialogue: 0,0:25:10.84,0:25:14.12,Default,,0,0,0,,我们先来考虑一下
Dialogue: 0,0:25:14.20,0:25:16.81,Default,,0,0,0,,这样一种有用的过程
Dialogue: 0,0:25:16.81,0:25:18.09,Default,,0,0,0,,假设我有一个流
Dialogue: 0,0:25:19.96,0:25:23.15,Default,,0,0,0,,流中的元素本身就是一个流
Dialogue: 0,0:25:23.98,0:25:26.53,Default,,0,0,0,,一开始是1、2、3
Dialogue: 0,0:25:32.72,0:25:33.88,Default,,0,0,0,,就是这样的一个流
Dialogue: 0,0:25:33.88,0:25:40.10,Default,,0,0,0,,流中的元素也是一个流
Dialogue: 0,0:25:40.97,0:25:43.42,Default,,0,0,0,,而我想要构建出一个流
Dialogue: 0,0:25:43.64,0:25:46.75,Default,,0,0,0,,用来收集所有的元素
Dialogue: 0,0:25:46.76,0:25:49.24,Default,,0,0,0,,把所有元素从子流中提取出来
Dialogue: 0,0:25:50.11,0:25:51.82,Default,,0,0,0,,最后把它们串接在一起
Dialogue: 0,0:25:52.27,0:25:55.61,Default,,0,0,0,,为了凸显使用这门语言多么简单
Dialogue: 0,0:25:56.11,0:25:57.10,Default,,0,0,0,,我们来定义这个FLATTEN过程
Dialogue: 0,0:25:57.95,0:26:10.64,Default,,0,0,0,,FLATTEN过程的参数是由流构成的流
Dialogue: 0,0:26:12.89,0:26:13.80,Default,,0,0,0,,那么 具体定义是怎样的呢?
Dialogue: 0,0:26:13.96,0:26:16.24,Default,,0,0,0,,它只是一个累积
Dialogue: 0,0:26:16.32,0:26:25.05,Default,,0,0,0,,我想用APPEND来做累积
Dialogue: 0,0:26:25.07,0:26:26.45,Default,,0,0,0,,也就是不断地做APPEND
Dialogue: 0,0:26:26.73,0:26:29.29,Default,,0,0,0,,所以我用APPEND-STREAM做累积
Dialogue: 0,0:26:35.90,0:26:48.20,Default,,0,0,0,,以THE-EMPTY-STREAM为初始值 累积这个流
Dialogue: 0,0:26:54.84,0:26:55.84,Default,,0,0,0,,这个例子告诉我们
Dialogue: 0,0:26:56.92,0:26:59.23,Default,,0,0,0,,你可以使用这些高阶过程
Dialogue: 0,0:26:59.60,0:27:00.83,Default,,0,0,0,,来做一些有趣的运算
Dialogue: 0,0:27:00.83,0:27:05.10,Default,,0,0,0,,事实上 我还想定义另一个实用过程
Dialogue: 0,0:27:05.10,0:27:07.05,Default,,0,0,0,,定义一个过程FLAT-MAP
Dialogue: 0,0:27:17.18,0:27:20.59,Default,,0,0,0,,它以一个过程和一个流为参数
Dialogue: 0,0:27:21.84,0:27:25.72,Default,,0,0,0,,其中S是一个流
Dialogue: 0,0:27:25.72,0:27:27.69,Default,,0,0,0,,F是一个过程
Dialogue: 0,0:27:27.72,0:27:30.62,Default,,0,0,0,,它作用于流中的每个元素 并产生一个新的流
Dialogue: 0,0:27:31.95,0:27:34.52,Default,,0,0,0,,我想从这些流中取出所有的元素
Dialogue: 0,0:27:35.00,0:27:36.00,Default,,0,0,0,,并把它们组合在一起
Dialogue: 0,0:27:36.00,0:27:49.13,Default,,0,0,0,,所以对应的代码就是 (FLATTEN (MAP F S))
Dialogue: 0,0:27:51.20,0:27:53.04,Default,,0,0,0,,每当我将F应用在S的某个元素上
Dialogue: 0,0:27:53.05,0:27:53.85,Default,,0,0,0,,我得到了一个流
Dialogue: 0,0:27:54.29,0:27:55.24,Default,,0,0,0,,执行完这条MAP语句后
Dialogue: 0,0:27:55.24,0:27:56.27,Default,,0,0,0,,我得到了一个由流构成的流
Dialogue: 0,0:27:56.46,0:27:57.42,Default,,0,0,0,,再把它进行FLATTEN
Dialogue: 0,0:27:58.67,0:28:02.64,Default,,0,0,0,,我想再使用这种方式
Dialogue: 0,0:28:03.87,0:28:05.84,Default,,0,0,0,,来解决另一个大家很熟悉的问题
Dialogue: 0,0:28:06.51,0:28:12.27,Default,,0,0,0,,这个问题和我们以前遇到过的许多问题一样
Dialogue: 0,0:28:12.28,0:28:13.96,Default,,0,0,0,,只是有些变型
Dialogue: 0,0:28:14.19,0:28:15.49,Default,,0,0,0,,给定整数N
Dialogue: 0,0:28:18.68,0:28:19.93,Default,,0,0,0,,我们的问题是
Dialogue: 0,0:28:21.20,0:28:31.53,Default,,0,0,0,,找出所有的整数序对(I, J)
Dialogue: 0,0:28:32.30,0:28:39.96,Default,,0,0,0,,其中 0 < J < I <= N
Dialogue: 0,0:28:42.33,0:28:52.03,Default,,0,0,0,,使得 I+J 是一个质数
Dialogue: 0,0:28:55.74,0:28:57.92,Default,,0,0,0,,如果N=6
Dialogue: 0,0:28:59.74,0:29:00.78,Default,,0,0,0,,我在这儿画个小表格
Dialogue: 0,0:29:01.55,0:29:06.67,Default,,0,0,0,,表头是I、J和I+J
Dialogue: 0,0:29:09.70,0:29:14.91,Default,,0,0,0,,比如说I=2 J=1 那么I+J就是3
Dialogue: 0,0:29:15.52,0:29:20.38,Default,,0,0,0,,然后I=3 J=2 那么I+J就是5
Dialogue: 0,0:29:21.21,0:29:26.51,Default,,0,0,0,,I=4 J=1 I+J=5也是一样的 等等
Dialogue: 0,0:29:26.92,0:29:28.11,Default,,0,0,0,,直到I到了6就终止了
Dialogue: 0,0:29:28.40,0:29:32.54,Default,,0,0,0,,我想要这个过程产生并返回这样的一个流
Dialogue: 0,0:29:33.20,0:29:37.04,Default,,0,0,0,,就是像 (I, J, I+J) 这样的三元组组成的流
Dialogue: 0,0:29:37.66,0:29:39.55,Default,,0,0,0,,对于每个整数N 我想得到一个这样流
Dialogue: 0,0:29:40.97,0:29:43.68,Default,,0,0,0,,听起来很简单
Dialogue: 0,0:29:43.68,0:29:44.35,Default,,0,0,0,,我们做做看
Dialogue: 0,0:29:47.23,0:29:48.22,Default,,0,0,0,,先这样开始
Dialogue: 0,0:29:50.15,0:29:54.25,Default,,0,0,0,,对于每一个整数 I
Dialogue: 0,0:29:55.24,0:29:56.44,Default,,0,0,0,,生成一个流
Dialogue: 0,0:29:57.00,0:29:58.59,Default,,0,0,0,,对于I从1取到N
Dialogue: 0,0:29:58.59,0:29:59.76,Default,,0,0,0,,每个I都生成一个流
Dialogue: 0,0:30:00.66,0:30:01.80,Default,,0,0,0,,这个流将会是什么样子?
Dialogue: 0,0:30:02.23,0:30:04.04,Default,,0,0,0,,我们先生成所有的序对
Dialogue: 0,0:30:04.18,0:30:07.55,Default,,0,0,0,,对于每个I 我们先生成
Dialogue: 0,0:30:08.43,0:30:14.52,Default,,0,0,0,,对于每个从1取到I-1的J
Dialogue: 0,0:30:16.91,0:30:17.98,Default,,0,0,0,,我们先生成序对
Dialogue: 0,0:30:18.35,0:30:20.71,Default,,0,0,0,,也就是只含有I和J的表
Dialogue: 0,0:30:23.78,0:30:27.10,Default,,0,0,0,,因此我们对整个区间做映射
Dialogue: 0,0:30:28.60,0:30:29.74,Default,,0,0,0,,生成序对
Dialogue: 0,0:30:31.07,0:30:33.17,Default,,0,0,0,,对于每个I 都生成一个序对流
Dialogue: 0,0:30:33.40,0:30:34.49,Default,,0,0,0,,最后进行FLATMAP
Dialogue: 0,0:30:34.59,0:30:36.20,Default,,0,0,0,,这样我们就生成了所有的(I, J)序对
Dialogue: 0,0:30:36.81,0:30:38.08,Default,,0,0,0,,其中I <= J
Dialogue: 0,0:30:38.73,0:30:39.85,Default,,0,0,0,,就是这样
Dialogue: 0,0:30:39.85,0:30:40.76,Default,,0,0,0,,紧接着就是过滤
Dialogue: 0,0:30:42.99,0:30:45.84,Default,,0,0,0,,我们对刚才FLATMAP得到的东西
Dialogue: 0,0:30:46.94,0:30:51.37,Default,,0,0,0,,我们以I -- 这里分别是 I 和 J
Dialogue: 0,0:30:51.66,0:30:54.17,Default,,0,0,0,,I是表的第一个元素
Dialogue: 0,0:30:54.30,0:30:55.60,Default,,0,0,0,,J是第二个
Dialogue: 0,0:30:57.21,0:31:00.01,Default,,0,0,0,,我们用一个谓词来判断 表中的两个元素
Dialogue: 0,0:31:00.22,0:31:02.00,Default,,0,0,0,,也就是表的CAR部分与CDR部分之和 是否为质数
Dialogue: 0,0:31:02.07,0:31:05.52,Default,,0,0,0,,用这个谓词来过滤刚刚收集起来的表
Dialogue: 0,0:31:06.54,0:31:07.85,Default,,0,0,0,,就得到了我们想要的表
Dialogue: 0,0:31:09.42,0:31:10.24,Default,,0,0,0,,然后我们继续
Dialogue: 0,0:31:10.88,0:31:13.10,Default,,0,0,0,,把过滤得到的结果 再次进行MAP操作
Dialogue: 0,0:31:13.26,0:31:19.05,Default,,0,0,0,,用来生成 I、J 和 I+J 构成的表
Dialogue: 0,0:31:19.61,0:31:21.39,Default,,0,0,0,,这就是过程 PRIME-SUM-PAIRS
Dialogue: 0,0:31:22.57,0:31:24.76,Default,,0,0,0,,最后只需要过一遍 这就是整个过程
Dialogue: 0,0:31:28.08,0:31:30.97,Default,,0,0,0,,一个MAP、一个FILTER 以及一个FLATMAP
Dialogue: 0,0:31:34.85,0:31:35.66,Default,,0,0,0,,所有的东西都在这里了
Dialogue: 0,0:31:35.66,0:31:37.12,Default,,0,0,0,,尽管可读性不是那么好
Dialogue: 0,0:31:37.42,0:31:38.94,Default,,0,0,0,,我们只是把中间过程展开了
Dialogue: 0,0:31:39.84,0:31:40.88,Default,,0,0,0,,这个例子
Dialogue: 0,0:31:43.28,0:31:45.00,Default,,0,0,0,,向我们展示了
Dialogue: 0,0:31:45.12,0:31:46.30,Default,,0,0,0,,嵌套循环
Dialogue: 0,0:31:47.66,0:31:50.09,Default,,0,0,0,,在这个过程中 它看起来就像
Dialogue: 0,0:31:50.11,0:31:52.81,Default,,0,0,0,,各种嵌套的MAP和FLATMAP的组合
Dialogue: 0,0:31:54.27,0:31:57.61,Default,,0,0,0,,所以我们不仅仅可以枚举单个个体
Dialogue: 0,0:31:57.61,0:31:58.81,Default,,0,0,0,,通过使用FLATMAP
Dialogue: 0,0:31:59.12,0:32:02.24,Default,,0,0,0,,我们可以实现其它语言中的嵌套循环
Dialogue: 0,0:32:03.23,0:32:03.76,Default,,0,0,0,,当然
Dialogue: 0,0:32:04.91,0:32:08.03,Default,,0,0,0,,重复写这些FLATMAP很烦人
Dialogue: 0,0:32:08.41,0:32:13.00,Default,,0,0,0,,尽管PRIME-SUM-PAIRS其中单独的部分很容易
Dialogue: 0,0:32:13.56,0:32:15.28,Default,,0,0,0,,但整体看起来还是十分复杂
Dialogue: 0,0:32:15.48,0:32:17.13,Default,,0,0,0,,如果你愿意的话 可以
Dialogue: 0,0:32:17.15,0:32:20.12,Default,,0,0,0,,引进一个叫COLLECT的语法糖衣
Dialogue: 0,0:32:21.04,0:32:22.68,Default,,0,0,0,,COLLECT只是一个缩写
Dialogue: 0,0:32:22.91,0:32:26.16,Default,,0,0,0,,用来代表特定顺序的FLATMAP和FILTER操作
Dialogue: 0,0:32:26.16,0:32:28.60,Default,,0,0,0,,这里我们用COLLECT把PRIME-SUM-PAIRS写一遍
Dialogue: 0,0:32:29.45,0:32:36.27,Default,,0,0,0,,PRIME-SUM-PAIRS过程需要收集这样一个东西
Dialogue: 0,0:32:36.52,0:32:39.20,Default,,0,0,0,,它的元素是形如(I, J, I+J)这样的表
Dialogue: 0,0:32:40.84,0:32:45.39,Default,,0,0,0,,而这将通过I从1取到N
Dialogue: 0,0:32:47.44,0:32:52.32,Default,,0,0,0,,同时J要从1取到I-1来产生
Dialogue: 0,0:32:54.16,0:32:56.54,Default,,0,0,0,,并且要满足I+J是质数
Dialogue: 0,0:32:58.04,0:33:00.32,Default,,0,0,0,,课堂上我就不讲解如何定义COLLECT了
Dialogue: 0,0:33:00.69,0:33:02.75,Default,,0,0,0,,书上面有
Dialogue: 0,0:33:03.42,0:33:05.45,Default,,0,0,0,,不过你可以清楚地看到 这些代码片段
Dialogue: 0,0:33:05.84,0:33:08.60,Default,,0,0,0,,就是我原先写的过程中的片段
Dialogue: 0,0:33:08.82,0:33:11.40,Default,,0,0,0,,COLLECT过程只是一个语法糖衣
Dialogue: 0,0:33:11.44,0:33:14.80,Default,,0,0,0,,用来自动生成嵌套FLATMAP
Dialogue: 0,0:33:16.31,0:33:20.33,Default,,0,0,0,,好的 我们再来看另一个例子
Dialogue: 0,0:33:20.67,0:33:22.00,Default,,0,0,0,,也展示了同样的道理
Dialogue: 0,0:33:22.12,0:33:23.53,Default,,0,0,0,,这是一个非常著名的问题
Dialogue: 0,0:33:24.70,0:33:28.75,Default,,0,0,0,,经常用来演示所谓的“回溯”算法
Dialogue: 0,0:33:28.76,0:33:30.20,Default,,0,0,0,,这就是“八皇后问题”
Dialogue: 0,0:33:30.20,0:33:31.08,Default,,0,0,0,,这是一个棋盘
Dialogue: 0,0:33:32.37,0:33:33.64,Default,,0,0,0,,八皇后问题要求我们
Dialogue: 0,0:33:33.64,0:33:35.85,Default,,0,0,0,,找到一种将八个皇后放到棋盘上的摆法
Dialogue: 0,0:33:36.44,0:33:38.00,Default,,0,0,0,,使得任意的两个皇后不会相互攻击
Dialogue: 0,0:33:38.00,0:33:40.60,Default,,0,0,0,,这里给出了一个解法
Dialogue: 0,0:33:41.21,0:33:43.68,Default,,0,0,0,,我需要保证摆放好后
Dialogue: 0,0:33:43.71,0:33:46.80,Default,,0,0,0,,任意两个皇后不在同一行或同一列上
Dialogue: 0,0:33:47.72,0:33:49.47,Default,,0,0,0,,也不在同一对角线上
Dialogue: 0,0:33:51.41,0:33:56.40,Default,,0,0,0,,有一个解决这个问题的标准解法
Dialogue: 0,0:33:59.74,0:34:01.48,Default,,0,0,0,,首先我们要做是
Dialogue: 0,0:34:02.54,0:34:04.62,Default,,0,0,0,,进入底层 站在George的层面
Dialogue: 0,0:34:04.94,0:34:08.09,Default,,0,0,0,,找到一种表示棋盘与位置的方式
Dialogue: 0,0:34:08.09,0:34:09.52,Default,,0,0,0,,这个并不需要太担心
Dialogue: 0,0:34:09.80,0:34:12.78,Default,,0,0,0,,假设我们有一个谓词SAFE?
Dialogue: 0,0:34:16.14,0:34:17.55,Default,,0,0,0,,SAFE?判断的是
Dialogue: 0,0:34:17.96,0:34:20.84,Default,,0,0,0,,假如一些皇后已经放在棋盘上
Dialogue: 0,0:34:21.36,0:34:24.54,Default,,0,0,0,,在这个点再放置一个皇后是否是安全?
Dialogue: 0,0:34:25.40,0:34:31.26,Default,,0,0,0,,所以SAFE?的参数分别为ROW和COLUMN
Dialogue: 0,0:34:32.76,0:34:35.47,Default,,0,0,0,,我将尝试把下一个皇后放在那个地方
Dialogue: 0,0:34:36.06,0:34:42.76,Default,,0,0,0,,另外一个参数是剩下的位置
Dialogue: 0,0:34:45.58,0:34:46.75,Default,,0,0,0,,SAFE?要判断的是
Dialogue: 0,0:34:46.86,0:34:51.68,Default,,0,0,0,,在这些位置已经放置了皇后的情况下
Dialogue: 0,0:34:53.02,0:34:54.76,Default,,0,0,0,,在这行这列放置皇后
Dialogue: 0,0:34:55.10,0:34:57.20,Default,,0,0,0,,是否安全
Dialogue: 0,0:34:58.30,0:34:59.36,Default,,0,0,0,,不用过分深究这个
Dialogue: 0,0:34:59.36,0:35:01.38,Default,,0,0,0,,那是George的问题 也不难写出来
Dialogue: 0,0:35:01.38,0:35:06.27,Default,,0,0,0,,只需要检测该行、该列
Dialogue: 0,0:35:06.30,0:35:08.52,Default,,0,0,0,,以及对角线上是否有东西即可
Dialogue: 0,0:35:10.53,0:35:13.12,Default,,0,0,0,,那么 有了这个过程后 我们的程序该如何组织呢?
Dialogue: 0,0:35:13.84,0:35:17.21,Default,,0,0,0,,有一种传统的方式
Dialogue: 0,0:35:17.93,0:35:18.97,Default,,0,0,0,,我们称为“回溯”
Dialogue: 0,0:35:20.52,0:35:23.21,Default,,0,0,0,,首先让我们来考虑
Dialogue: 0,0:35:25.13,0:35:28.88,Default,,0,0,0,,把第一个皇后放在第一列的
Dialogue: 0,0:35:30.04,0:35:31.34,Default,,0,0,0,,所有方式
Dialogue: 0,0:35:31.45,0:35:32.24,Default,,0,0,0,,有8种
Dialogue: 0,0:35:32.58,0:35:35.00,Default,,0,0,0,,先试下第一列
Dialogue: 0,0:35:35.88,0:35:37.30,Default,,0,0,0,,第一行第一列
Dialogue: 0,0:35:37.30,0:35:38.70,Default,,0,0,0,,每个分支都代表了
Dialogue: 0,0:35:40.17,0:35:41.88,Default,,0,0,0,,在每一个层次的可能解
Dialogue: 0,0:35:43.36,0:35:45.53,Default,,0,0,0,,我试着把皇后放在第一列
Dialogue: 0,0:35:46.14,0:35:47.74,Default,,0,0,0,,现在 我在第一列放置好一个皇后以后
Dialogue: 0,0:35:47.77,0:35:49.98,Default,,0,0,0,,我又尝试在第一列放置下一个皇后
Dialogue: 0,0:35:50.60,0:35:52.17,Default,,0,0,0,,并不成功 它们都……
Dialogue: 0,0:35:53.31,0:35:54.60,Default,,0,0,0,,我尝试把第一个皇后
Dialogue: 0,0:35:54.86,0:35:56.80,Default,,0,0,0,,把在第一列上的那个皇后 放在第一行
Dialogue: 0,0:35:56.92,0:35:57.47,Default,,0,0,0,,不好意思
Dialogue: 0,0:35:59.05,0:36:01.39,Default,,0,0,0,,放好后 我们再把下一个皇后放在第一行
Dialogue: 0,0:36:01.39,0:36:02.09,Default,,0,0,0,,这不行
Dialogue: 0,0:36:02.09,0:36:03.18,Default,,0,0,0,,所以又回到这里
Dialogue: 0,0:36:04.20,0:36:04.72,Default,,0,0,0,,然后再考虑
Dialogue: 0,0:36:04.83,0:36:06.86,Default,,0,0,0,,我们把这个皇后放在第二行吗?
Dialogue: 0,0:36:07.32,0:36:08.38,Default,,0,0,0,,然而也不行
Dialogue: 0,0:36:08.55,0:36:09.76,Default,,0,0,0,,那么放在第三行呢?
Dialogue: 0,0:36:09.76,0:36:10.52,Default,,0,0,0,,这样可以
Dialogue: 0,0:36:12.79,0:36:15.13,Default,,0,0,0,,下一个皇后可以放在第一列吗?
Dialogue: 0,0:36:15.38,0:36:17.82,Default,,0,0,0,,我不能再画更多的棋盘了
Dialogue: 0,0:36:17.82,0:36:18.86,Default,,0,0,0,,但我先假设这个可行
Dialogue: 0,0:36:19.19,0:36:20.45,Default,,0,0,0,,我尝试下一个
Dialogue: 0,0:36:20.45,0:36:24.17,Default,,0,0,0,,在每一个地方 尽可能的沿着树往下
Dialogue: 0,0:36:24.54,0:36:25.64,Default,,0,0,0,,然后回退
Dialogue: 0,0:36:25.64,0:36:28.97,Default,,0,0,0,,如果我从这里往下走 发现下面不可能有解
Dialogue: 0,0:36:29.00,0:36:30.12,Default,,0,0,0,,我就回溯到这里来
Dialogue: 0,0:36:30.28,0:36:32.44,Default,,0,0,0,,然后开始生成这个子树
Dialogue: 0,0:36:33.26,0:36:34.32,Default,,0,0,0,,我就像这样遍历
Dialogue: 0,0:36:35.05,0:36:37.26,Default,,0,0,0,,最后 一路求解下来
Dialogue: 0,0:36:37.72,0:36:38.59,Default,,0,0,0,,就会得到答案
Dialogue: 0,0:36:39.82,0:36:41.98,Default,,0,0,0,,这种典型的范式
Dialogue: 0,0:36:43.12,0:36:45.93,Default,,0,0,0,,之前被广泛地使用在人工智能编程中
Dialogue: 0,0:36:45.93,0:36:47.30,Default,,0,0,0,,术语叫做 “回溯搜索”
Dialogue: 0,0:36:57.47,0:37:03.04,Default,,0,0,0,,这真的没有必要
Dialogue: 0,0:37:03.86,0:37:06.55,Default,,0,0,0,,你们也发现了 我在可视化这个过程时也犯了迷糊
Dialogue: 0,0:37:06.81,0:37:08.25,Default,,0,0,0,,你们也看到了复杂程度
Dialogue: 0,0:37:08.55,0:37:10.76,Default,,0,0,0,,而且这种复杂还很难描述
Dialogue: 0,0:37:10.76,0:37:11.82,Default,,0,0,0,,为什么会这样?
Dialogue: 0,0:37:12.39,0:37:13.29,Default,,0,0,0,,这是因为
Dialogue: 0,0:37:13.53,0:37:17.39,Default,,0,0,0,,这是因为这程序过分地关注于时间了
Dialogue: 0,0:37:18.58,0:37:20.43,Default,,0,0,0,,这之中太多 -- 先试试这个 再试试这个
Dialogue: 0,0:37:20.49,0:37:22.38,Default,,0,0,0,,再回到上一个可行的地方 -- 这种操作太多了
Dialogue: 0,0:37:22.89,0:37:24.34,Default,,0,0,0,,这很复杂
Dialogue: 0,0:37:24.34,0:37:26.36,Default,,0,0,0,,如果我们不再如此关注时间
Dialogue: 0,0:37:28.04,0:37:29.76,Default,,0,0,0,,就有一个更简单的方式来描述
Dialogue: 0,0:37:31.20,0:37:32.36,Default,,0,0,0,,让我们来想象一下
Dialogue: 0,0:37:33.31,0:37:36.57,Default,,0,0,0,,现在我有
Dialogue: 0,0:37:38.32,0:37:42.16,Default,,0,0,0,,有一个高达K-1层的树
Dialogue: 0,0:37:43.40,0:37:46.32,Default,,0,0,0,,假设我已经有了
Dialogue: 0,0:37:48.09,0:37:52.19,Default,,0,0,0,,把皇后放在前K列的所有解法
Dialogue: 0,0:37:53.56,0:37:54.61,Default,,0,0,0,,假设是这样
Dialogue: 0,0:37:54.61,0:37:55.79,Default,,0,0,0,,不要担心我是怎么得到的
Dialogue: 0,0:37:57.07,0:37:59.20,Default,,0,0,0,,现在 如何扩充下去呢?
Dialogue: 0,0:37:59.20,0:38:02.16,Default,,0,0,0,,怎样找到在下一列中放皇后的所有可行方法?
Dialogue: 0,0:38:02.48,0:38:03.13,Default,,0,0,0,,很简单
Dialogue: 0,0:38:03.62,0:38:06.41,Default,,0,0,0,,对于已有的位置
Dialogue: 0,0:38:07.82,0:38:13.96,Default,,0,0,0,,我考虑把下一个皇后放在每一行上
Dialogue: 0,0:38:15.08,0:38:16.16,Default,,0,0,0,,来构建出下一步的棋局
Dialogue: 0,0:38:16.16,0:38:17.29,Default,,0,0,0,,然后 把所有放置的位置
Dialogue: 0,0:38:17.44,0:38:19.71,Default,,0,0,0,,用SAFE?进行过滤
Dialogue: 0,0:38:21.80,0:38:22.99,Default,,0,0,0,,不像之前那样
Dialogue: 0,0:38:22.99,0:38:24.67,Default,,0,0,0,,把这个树看做是逐步生成的
Dialogue: 0,0:38:24.94,0:38:26.86,Default,,0,0,0,,我们假设所有的东西都生成好了
Dialogue: 0,0:38:29.68,0:38:32.41,Default,,0,0,0,,为了从K-1层扩展到K层
Dialogue: 0,0:38:32.64,0:38:36.24,Default,,0,0,0,,我只需要扩展所有可能的放置方法
Dialogue: 0,0:38:36.48,0:38:37.80,Default,,0,0,0,,最后保留安全的排列
Dialogue: 0,0:38:37.80,0:38:39.23,Default,,0,0,0,,就得到一个K层树的结果
Dialogue: 0,0:38:39.30,0:38:40.67,Default,,0,0,0,,这是解决八皇后问题
Dialogue: 0,0:38:40.89,0:38:42.17,Default,,0,0,0,,的一个递归策略
Dialogue: 0,0:38:44.53,0:38:45.34,Default,,0,0,0,,好的 我们来看看
Dialogue: 0,0:38:50.33,0:38:52.68,Default,,0,0,0,,我们编写子过程FILL-COLS
Dialogue: 0,0:38:53.00,0:38:55.53,Default,,0,0,0,,来解决在一个特定大小棋盘上的
Dialogue: 0,0:38:58.92,0:39:01.03,Default,,0,0,0,,八皇后问题
Dialogue: 0,0:39:01.13,0:39:04.86,Default,,0,0,0,,这个过程会把皇后放置到K个列中
Dialogue: 0,0:39:06.35,0:39:07.70,Default,,0,0,0,,这是递归的模式
Dialogue: 0,0:39:07.70,0:39:10.92,Default,,0,0,0,,最后会以棋盘的大小为参数 调用FILL-COLS
Dialogue: 0,0:39:12.99,0:39:15.28,Default,,0,0,0,,FILL-COLS是用来说明
Dialogue: 0,0:39:15.29,0:39:17.16,Default,,0,0,0,,如何安全地把皇后放置在
Dialogue: 0,0:39:17.20,0:39:19.58,Default,,0,0,0,,具有SIZE行的棋盘的前K列
Dialogue: 0,0:39:20.36,0:39:21.64,Default,,0,0,0,,如果K是0
Dialogue: 0,0:39:22.27,0:39:23.60,Default,,0,0,0,,就不用做什么
Dialogue: 0,0:39:23.94,0:39:25.93,Default,,0,0,0,,结果是一个空棋盘
Dialogue: 0,0:39:26.71,0:39:28.07,Default,,0,0,0,,否则就做点别的
Dialogue: 0,0:39:28.35,0:39:29.44,Default,,0,0,0,,这里将要使用COLLECT
Dialogue: 0,0:39:30.81,0:39:31.77,Default,,0,0,0,,完整的代码在这里
Dialogue: 0,0:39:34.33,0:39:41.91,Default,,0,0,0,,我找到了所有在前K-1列中放皇后的方法
Dialogue: 0,0:39:42.19,0:39:43.32,Default,,0,0,0,,这是我所假设的
Dialogue: 0,0:39:43.32,0:39:46.36,Default,,0,0,0,,想像这棵树下降到K-1层
Dialogue: 0,0:39:48.88,0:39:52.11,Default,,0,0,0,,然后我尝试每一行
Dialogue: 0,0:39:52.52,0:39:54.13,Default,,0,0,0,,尝试每一个可行的行
Dialogue: 0,0:39:54.13,0:39:55.04,Default,,0,0,0,,总共SIZE行
Dialogue: 0,0:39:55.31,0:39:56.49,Default,,0,0,0,,这里枚举了所有行数
Dialogue: 0,0:39:58.04,0:39:59.79,Default,,0,0,0,,现在要做的是
Dialogue: 0,0:40:03.15,0:40:05.82,Default,,0,0,0,,把我将要尝试的新行和第K列
Dialogue: 0,0:40:07.95,0:40:08.95,Default,,0,0,0,,收集起来
Dialogue: 0,0:40:08.95,0:40:10.09,Default,,0,0,0,,我邻接一个位置
Dialogue: 0,0:40:10.20,0:40:11.29,Default,,0,0,0,,这是George的问题了
Dialogue: 0,0:40:11.29,0:40:12.75,Default,,0,0,0,,实现ADJOIN-POSITION和SAFE?都是George的工作
Dialogue: 0,0:40:13.64,0:40:15.28,Default,,0,0,0,,这个过程需要的参数有
Dialogue: 0,0:40:15.50,0:40:17.04,Default,,0,0,0,,ROW、COL以及REST-OF-POS
Dialogue: 0,0:40:17.07,0:40:19.02,Default,,0,0,0,,然后返回位置的集合
Dialogue: 0,0:40:19.66,0:40:25.77,Default,,0,0,0,,我把新的行和列
Dialogue: 0,0:40:26.06,0:40:27.68,Default,,0,0,0,,和剩下的皇后邻接起来
Dialogue: 0,0:40:28.57,0:40:29.76,Default,,0,0,0,,那些剩下的皇后
Dialogue: 0,0:40:29.92,0:40:31.45,Default,,0,0,0,,会尝试所有的
Dialogue: 0,0:40:31.87,0:40:34.16,Default,,0,0,0,,放置在K-1列中的可行解
Dialogue: 0,0:40:34.62,0:40:37.04,Default,,0,0,0,,新的行遍历了所有的可能性
Dialogue: 0,0:40:37.85,0:40:40.76,Default,,0,0,0,,过滤出安全的位置
Dialogue: 0,0:40:43.24,0:40:44.70,Default,,0,0,0,,这就是整个程序了
Dialogue: 0,0:40:46.33,0:40:47.31,Default,,0,0,0,,整个过程
Dialogue: 0,0:40:49.84,0:40:52.43,Default,,0,0,0,,它不仅找到了八皇后的问题的解
Dialogue: 0,0:40:53.42,0:40:56.68,Default,,0,0,0,,它还给出了所有的解
Dialogue: 0,0:40:56.68,0:40:58.48,Default,,0,0,0,,运行结束之后 就得到一个流
Dialogue: 0,0:40:58.48,0:41:01.90,Default,,0,0,0,,流中的元素是所有的解
Dialogue: 0,0:41:05.31,0:41:06.26,Default,,0,0,0,,为什么这个更简单一点呢?
Dialogue: 0,0:41:06.26,0:41:08.54,Default,,0,0,0,,我们完全没有把这个当做
Dialogue: 0,0:41:08.88,0:41:11.52,Default,,0,0,0,,按时间发生的、具有状态的过程
Dialogue: 0,0:41:12.72,0:41:14.42,Default,,0,0,0,,我们只说 这是一些东西的集合
Dialogue: 0,0:41:14.94,0:41:16.00,Default,,0,0,0,,这是它更加简单的原因
Dialogue: 0,0:41:18.00,0:41:20.11,Default,,0,0,0,,我们已经转变了观念
Dialogue: 0,0:41:20.11,0:41:22.59,Default,,0,0,0,,还记得吗 这节课开始我们就讲过
Dialogue: 0,0:41:22.82,0:41:26.23,Default,,0,0,0,,我们转变了建模的观念
Dialogue: 0,0:41:26.23,0:41:29.20,Default,,0,0,0,,我们不再把事物看做按时间演进
Dialogue: 0,0:41:29.37,0:41:31.31,Default,,0,0,0,,也不再具有不同的阶段与状态
Dialogue: 0,0:41:31.75,0:41:33.79,Default,,0,0,0,,取而代之的是 我们对全局进行建模
Dialogue: 0,0:41:33.80,0:41:35.93,Default,,0,0,0,,我们关注粉笔的整个飞行过程
Dialogue: 0,0:41:36.28,0:41:38.88,Default,,0,0,0,,而不是专注于每个瞬时状态
Dialogue: 0,0:41:40.75,0:41:41.44,Default,,0,0,0,,有什么问题吗?
Dialogue: 0,0:41:44.08,0:41:46.20,Default,,0,0,0,,学生:在我看来回溯会
Dialogue: 0,0:41:46.22,0:41:48.96,Default,,0,0,0,,搜索到它所能找到的第一个解
Dialogue: 0,0:41:49.31,0:41:51.48,Default,,0,0,0,,而这个递归搜索
Dialogue: 0,0:41:51.48,0:41:53.26,Default,,0,0,0,,会去寻找所有的解
Dialogue: 0,0:41:53.32,0:41:53.60,Default,,0,0,0,,教授:是这样的
Dialogue: 0,0:41:54.03,0:41:55.26,Default,,0,0,0,,学生:但问题是
Dialogue: 0,0:41:55.26,0:41:57.92,Default,,0,0,0,,如果需要搜索的空间足够的大
Dialogue: 0,0:41:57.92,0:42:00.92,Default,,0,0,0,,第二种搜索方式就会变得不现实
Dialogue: 0,0:42:01.36,0:42:05.93,Default,,0,0,0,,教授:呃 这个问题其实是
Dialogue: 0,0:42:07.13,0:42:08.44,Default,,0,0,0,,这一节课剩下的内容
Dialogue: 0,0:42:08.57,0:42:10.54,Default,,0,0,0,,这个问题很好
Dialogue: 0,0:42:13.87,0:42:15.74,Default,,0,0,0,,先不要尝试去预知后面的课
Dialogue: 0,0:42:15.96,0:42:19.23,Default,,0,0,0,,只是在现在 你们要保持谨慎
Dialogue: 0,0:42:19.84,0:42:21.84,Default,,0,0,0,,这里确实有点奇怪 难道不是么?
Dialogue: 0,0:42:22.22,0:42:24.51,Default,,0,0,0,,尽管这个看起来不错 但是难道它不低效吗?
Dialogue: 0,0:42:24.83,0:42:26.03,Default,,0,0,0,,这是我们待会儿要解决的问题
Dialogue: 0,0:42:28.10,0:42:30.02,Default,,0,0,0,,就让我们稍后来揭晓秘密吧
Dialogue: 0,0:42:33.35,0:42:34.60,Default,,0,0,0,,好吧 休息一下
Dialogue: 0,0:42:34.60,0:42:44.51,Default,,0,0,0,,[音乐]
Dialogue: 0,0:42:44.51,0:42:49.04,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》
Dialogue: 0,0:43:10.57,0:43:17.05,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授
Dialogue: 0,0:43:17.05,0:43:21.21,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》
Dialogue: 0,0:43:21.21,0:43:25.21,Declare,,0,0,0,,{\an2\fad(500,500)} I
Dialogue: 0,0:43:29.65,0:43:33.76,Default,,0,0,0,,你可能现在开始怀疑了
Dialogue: 0,0:43:35.60,0:43:39.26,Default,,0,0,0,,我已经展示了这种简单而优雅的
Dialogue: 0,0:43:40.51,0:43:42.28,Default,,0,0,0,,组合程序的方法
Dialogue: 0,0:43:42.86,0:43:46.91,Default,,0,0,0,,这跟那些传统程序非常不同
Dialogue: 0,0:43:46.92,0:43:48.19,Default,,0,0,0,,那些求奇数的平方和
Dialogue: 0,0:43:48.72,0:43:51.32,Default,,0,0,0,,或者求奇数项斐波那契数之类的程序
Dialogue: 0,0:43:53.74,0:43:55.48,Default,,0,0,0,,也不像那些混合了
Dialogue: 0,0:43:55.85,0:43:58.84,Default,,0,0,0,,枚举函数、过滤函数和累积函数的程序
Dialogue: 0,0:44:00.44,0:44:01.82,Default,,0,0,0,,通过把它们混合起来
Dialogue: 0,0:44:02.20,0:44:04.59,Default,,0,0,0,,通过这种混搭式的
Dialogue: 0,0:44:04.62,0:44:07.34,Default,,0,0,0,,组合程序的方法
Dialogue: 0,0:44:07.82,0:44:09.53,Default,,0,0,0,,我们并没有获得
Dialogue: 0,0:44:09.55,0:44:11.77,Default,,0,0,0,,流式程序设计的理论优势
Dialogue: 0,0:44:13.80,0:44:14.25,Default,,0,0,0,,另一方面
Dialogue: 0,0:44:14.28,0:44:16.88,Default,,0,0,0,,你们所见过的大多数程序是那种丑陋的风格
Dialogue: 0,0:44:18.34,0:44:18.94,Default,,0,0,0,,为什么会这样?
Dialogue: 0,0:44:19.20,0:44:20.59,Default,,0,0,0,,难道计算机科学家们
Dialogue: 0,0:44:21.16,0:44:24.30,Default,,0,0,0,,愚蠢得无以复加
Dialogue: 0,0:44:25.42,0:44:26.44,Default,,0,0,0,,以至于他们没有注意到这个现象么?
Dialogue: 0,0:44:27.07,0:44:28.75,Default,,0,0,0,,如果你仅仅只是做了这些事
Dialogue: 0,0:44:29.63,0:44:31.93,Default,,0,0,0,,你就能让程序变得极其优雅么?
Dialogue: 0,0:44:33.62,0:44:34.78,Default,,0,0,0,,肯定有什么窍门
Dialogue: 0,0:44:36.76,0:44:39.05,Default,,0,0,0,,事实上这一窍门也很容易发现
Dialogue: 0,0:44:39.51,0:44:41.74,Default,,0,0,0,,我们来看看接下来的这个问题
Dialogue: 0,0:44:42.03,0:44:45.47,Default,,0,0,0,,假设我让你去找
Dialogue: 0,0:44:46.16,0:44:48.16,Default,,0,0,0,,1,000到1,000,000之间的第二个素数
Dialogue: 0,0:44:49.12,0:44:50.56,Default,,0,0,0,,如果你的计算机性能更强劲的话
Dialogue: 0,0:44:50.59,0:44:53.05,Default,,0,0,0,,或者可以去找10,000到100,000,000之间的
Dialogue: 0,0:44:54.32,0:44:55.45,Default,,0,0,0,,你可能觉得这很容易
Dialogue: 0,0:44:55.47,0:44:56.65,Default,,0,0,0,,我可以用流来解决
Dialogue: 0,0:44:57.08,0:44:59.87,Default,,0,0,0,,我需要做的就是
Dialogue: 0,0:45:00.57,0:45:02.89,Default,,0,0,0,,从10,000枚举到1,000,000
Dialogue: 0,0:45:04.16,0:45:06.51,Default,,0,0,0,,我就获得了从10,000到1,000,000的所有整数
Dialogue: 0,0:45:06.80,0:45:08.64,Default,,0,0,0,,我过滤出所有的质数
Dialogue: 0,0:45:09.39,0:45:11.10,Default,,0,0,0,,也就是对这些数做素性检测
Dialogue: 0,0:45:11.76,0:45:12.83,Default,,0,0,0,,然后从中取出第二个元素
Dialogue: 0,0:45:12.84,0:45:14.04,Default,,0,0,0,,也就是 TAIL的HEAD部分
Dialogue: 0,0:45:15.79,0:45:17.38,Default,,0,0,0,,这显然是非常荒谬的
Dialogue: 0,0:45:21.66,0:45:23.20,Default,,0,0,0,,我们的机器没有这么大的空间
Dialogue: 0,0:45:23.58,0:45:25.24,Default,,0,0,0,,来存放这些整数
Dialogue: 0,0:45:25.28,0:45:26.35,Default,,0,0,0,,更别说来测试它们了
Dialogue: 0,0:45:27.04,0:45:28.64,Default,,0,0,0,,而且我也只是取第二个数而已
Dialogue: 0,0:45:29.81,0:45:34.94,Default,,0,0,0,,这种传统程序设计风格的威力
Dialogue: 0,0:45:36.43,0:45:37.68,Default,,0,0,0,,(虽然)也正是其弱点
Dialogue: 0,0:45:37.96,0:45:38.94,Default,,0,0,0,,这种程序设计风格
Dialogue: 0,0:45:39.61,0:45:43.50,Default,,0,0,0,,混合了枚举、测试以及累积
Dialogue: 0,0:45:44.88,0:45:46.46,Default,,0,0,0,,我们不需要做全部的事
Dialogue: 0,0:45:46.67,0:45:49.18,Default,,0,0,0,,所以说 实际上这是这种
Dialogue: 0,0:45:49.45,0:45:51.74,Default,,0,0,0,,概念上丑陋的风格
Dialogue: 0,0:45:52.20,0:45:53.80,Default,,0,0,0,,正是让它运行起来高效
Dialogue: 0,0:45:54.91,0:45:55.84,Default,,0,0,0,,就是像这样来混合
Dialogue: 0,0:45:57.80,0:45:59.34,Default,,0,0,0,,我今天一早上所做的好像都是在
Dialogue: 0,0:45:59.34,0:46:00.42,Default,,0,0,0,,把你们搞糊涂一样
Dialogue: 0,0:46:00.42,0:46:03.10,Default,,0,0,0,,我为你们展示了一种貌似可行的优雅程序设计方法
Dialogue: 0,0:46:03.10,0:46:03.96,Default,,0,0,0,,但它却不可行
Dialogue: 0,0:46:05.84,0:46:08.32,Default,,0,0,0,,但是 接下来就是见证奇迹的时刻
Dialogue: 0,0:46:09.04,0:46:10.57,Default,,0,0,0,,结果却是 这个游戏里
Dialogue: 0,0:46:11.21,0:46:13.84,Default,,0,0,0,,我们真的可以得到蛋糕并吃掉它
Dialogue: 0,0:46:14.87,0:46:16.11,Default,,0,0,0,,我的意思是
Dialogue: 0,0:46:18.09,0:46:21.15,Default,,0,0,0,,我们完全可以用流来组织程序
Dialogue: 0,0:46:21.16,0:46:22.48,Default,,0,0,0,,就像我之前编写的那样
Dialogue: 0,0:46:23.55,0:46:27.74,Default,,0,0,0,,以至于当机器真正运行的时候
Dialogue: 0,0:46:28.33,0:46:31.52,Default,,0,0,0,,它可以和传统风格的程序一样高效
Dialogue: 0,0:46:31.71,0:46:34.28,Default,,0,0,0,,那些混合了生成与测试的程序
Dialogue: 0,0:46:36.16,0:46:38.80,Default,,0,0,0,,听起来不可思议
Dialogue: 0,0:46:40.77,0:46:41.82,Default,,0,0,0,,关键在就于
Dialogue: 0,0:46:42.00,0:46:43.69,Default,,0,0,0,,流不是表
Dialogue: 0,0:46:48.09,0:46:49.79,Default,,0,0,0,,一会儿我们就会看到 但是现在
Dialogue: 0,0:46:49.80,0:46:51.77,Default,,0,0,0,,先让我们来看看幻灯片
Dialogue: 0,0:46:52.24,0:46:53.80,Default,,0,0,0,,你们对这个
Dialogue: 0,0:46:53.84,0:46:55.58,Default,,0,0,0,,信号处理系统的印象是
Dialogue: 0,0:46:57.26,0:46:58.72,Default,,0,0,0,,你们认为要发生的是
Dialogue: 0,0:46:59.13,0:47:00.92,Default,,0,0,0,,在这类盒子中
Dialogue: 0,0:47:01.18,0:47:03.58,Default,,0,0,0,,事先产生好了整数
Dialogue: 0,0:47:05.36,0:47:06.40,Default,,0,0,0,,这里有个过滤函数
Dialogue: 0,0:47:07.45,0:47:09.37,Default,,0,0,0,,它和那个盒子相连 并从中拉取东西
Dialogue: 0,0:47:10.94,0:47:13.15,Default,,0,0,0,,这里还有人从这整个系统中
Dialogue: 0,0:47:13.31,0:47:14.91,Default,,0,0,0,,拉取东西
Dialogue: 0,0:47:16.79,0:47:18.70,Default,,0,0,0,,你们应该这么来理解:
Dialogue: 0,0:47:18.99,0:47:20.72,Default,,0,0,0,,有人想要得到第一个质数
Dialogue: 0,0:47:22.67,0:47:24.14,Default,,0,0,0,,他从这个过滤函数这儿拉取
Dialogue: 0,0:47:24.59,0:47:26.12,Default,,0,0,0,,FILTER从枚举函数中去拉取
Dialogue: 0,0:47:28.02,0:47:29.15,Default,,0,0,0,,你只需要在固定范围内寻找
Dialogue: 0,0:47:29.16,0:47:30.93,Default,,0,0,0,,然后从里面取出第二个数
Dialogue: 0,0:47:30.93,0:47:31.95,Default,,0,0,0,,第二个质数是多少?
Dialogue: 0,0:47:33.71,0:47:35.37,Default,,0,0,0,,没有额外的计算
Dialogue: 0,0:47:35.37,0:47:36.64,Default,,0,0,0,,只要你不去拉取东西
Dialogue: 0,0:47:36.64,0:47:38.32,Default,,0,0,0,,就不会产生进行额外计算
Dialogue: 0,0:47:40.50,0:47:41.41,Default,,0,0,0,,我来用实物演示一下
Dialogue: 0,0:47:41.41,0:47:43.88,Default,,0,0,0,,这个小设备
Dialogue: 0,0:47:43.90,0:47:44.97,Default,,0,0,0,,这是个小型的流机器
Dialogue: 0,0:47:45.50,0:47:46.83,Default,,0,0,0,,这是Eric Grimson发明的
Dialogue: 0,0:47:47.60,0:47:49.24,Default,,0,0,0,,他也在MIT教这门课
Dialogue: 0,0:47:49.83,0:47:52.51,Default,,0,0,0,,实际的流程是 -- 这里有某种流
Dialogue: 0,0:47:52.54,0:47:53.82,Default,,0,0,0,,就像一串整数一样
Dialogue: 0,0:47:54.78,0:47:56.33,Default,,0,0,0,,这些是一些处理单元
Dialogue: 0,0:47:58.70,0:48:02.60,Default,,0,0,0,,就像是FILTER、MAP之类的东西
Dialogue: 0,0:48:03.98,0:48:09.18,Default,,0,0,0,,如果我把流实现为表 来进行处理
Dialogue: 0,0:48:09.24,0:48:11.26,Default,,0,0,0,,我拥有的是一个表
Dialogue: 0,0:48:11.47,0:48:12.67,Default,,0,0,0,,现在 我先执行第一个过滤函数
Dialogue: 0,0:48:12.67,0:48:14.07,Default,,0,0,0,,我像这样完全处理
Dialogue: 0,0:48:14.88,0:48:15.77,Default,,0,0,0,,针对这个流
Dialogue: 0,0:48:16.32,0:48:19.21,Default,,0,0,0,,不断地处理、处理、处理、处理
Dialogue: 0,0:48:19.61,0:48:21.05,Default,,0,0,0,,然后得到一个新的流
Dialogue: 0,0:48:21.63,0:48:24.07,Default,,0,0,0,,现在 我把得到的结果拿在我手中
Dialogue: 0,0:48:24.07,0:48:25.26,Default,,0,0,0,,然后把它放进第二个
Dialogue: 0,0:48:25.56,0:48:26.94,Default,,0,0,0,,又处理了全部的流
Dialogue: 0,0:48:28.27,0:48:29.51,Default,,0,0,0,,得到一个新流
Dialogue: 0,0:48:32.13,0:48:33.36,Default,,0,0,0,,然后我再把结果
Dialogue: 0,0:48:34.28,0:48:36.36,Default,,0,0,0,,用相同的方式再次处理
Dialogue: 0,0:48:36.36,0:48:40.99,Default,,0,0,0,,如果仅仅把流当做表的话
Dialogue: 0,0:48:41.69,0:48:42.97,Default,,0,0,0,,计算的过程就是这样的
Dialogue: 0,0:48:43.86,0:48:45.64,Default,,0,0,0,,但是事实上 流不是表 流就是流
Dialogue: 0,0:48:45.82,0:48:48.11,Default,,0,0,0,,而你们应该这样来想像
Dialogue: 0,0:48:50.23,0:48:52.52,Default,,0,0,0,,我把这些小玩意连接起来
Dialogue: 0,0:48:55.26,0:48:56.76,Default,,0,0,0,,数据在其中流动
Dialogue: 0,0:49:00.33,0:49:02.30,Default,,0,0,0,,这里是流的源头
Dialogue: 0,0:49:02.32,0:49:02.92,Default,,0,0,0,,它可能在
Dialogue: 0,0:49:04.19,0:49:05.72,Default,,0,0,0,,产生一些整数
Dialogue: 0,0:49:05.98,0:49:07.39,Default,,0,0,0,,如果我想要拉取一个结果 会发生什么?
Dialogue: 0,0:49:07.58,0:49:08.91,Default,,0,0,0,,我从尾部这里拉取
Dialogue: 0,0:49:10.20,0:49:11.07,Default,,0,0,0,,而这个单元会说
Dialogue: 0,0:49:11.08,0:49:12.20,Default,,0,0,0,,我需要更多的数据
Dialogue: 0,0:49:13.09,0:49:15.52,Default,,0,0,0,,所以 它就到这个单元去拉取数据
Dialogue: 0,0:49:15.83,0:49:17.39,Default,,0,0,0,,它说:“我需要更多的数据”
Dialogue: 0,0:49:17.89,0:49:19.56,Default,,0,0,0,,然后这个又从下一个单元拉取
Dialogue: 0,0:49:19.56,0:49:20.28,Default,,0,0,0,,可能是一个过滤函数
Dialogue: 0,0:49:20.28,0:49:21.40,Default,,0,0,0,,从它那里取得更多数据
Dialogue: 0,0:49:21.64,0:49:23.15,Default,,0,0,0,,我在这一端拉取数据时
Dialogue: 0,0:49:23.53,0:49:25.56,Default,,0,0,0,,只会生成这么多的数据
Dialogue: 0,0:49:25.78,0:49:28.30,Default,,0,0,0,,我在另一端请求一定量的数据时
Dialogue: 0,0:49:28.56,0:49:29.98,Default,,0,0,0,,只有相当数量的数据被生成并处理
Dialogue: 0,0:49:30.76,0:49:32.09,Default,,0,0,0,,这就是你们需要知道的
Dialogue: 0,0:49:32.80,0:49:34.38,Default,,0,0,0,,把流实现为表
Dialogue: 0,0:49:34.56,0:49:35.92,Default,,0,0,0,,和流真实的工作方式
Dialogue: 0,0:49:36.16,0:49:37.50,Default,,0,0,0,,的区别
Dialogue: 0,0:49:40.78,0:49:42.14,Default,,0,0,0,,那么 到底怎么来实现呢?
Dialogue: 0,0:49:42.35,0:49:43.32,Default,,0,0,0,,知道了流的真实工作方式
Dialogue: 0,0:49:43.40,0:49:44.52,Default,,0,0,0,,构造流有什么窍门呢?
Dialogue: 0,0:49:47.93,0:49:50.32,Default,,0,0,0,,我们想要把流组织成
Dialogue: 0,0:49:50.41,0:49:51.58,Default,,0,0,0,,一种数据结构
Dialogue: 0,0:49:52.00,0:49:54.22,Default,,0,0,0,,它能够增量式地计算自己
Dialogue: 0,0:49:54.22,0:49:56.22,Default,,0,0,0,,一种“按需”数据结构
Dialogue: 0,0:49:58.96,0:50:00.51,Default,,0,0,0,,基本思想在于
Dialogue: 0,0:50:00.97,0:50:02.70,Default,,0,0,0,,再次强调 这是贯穿整个课程的
Dialogue: 0,0:50:02.72,0:50:04.12,Default,,0,0,0,,几大基本思想之一
Dialogue: 0,0:50:04.49,0:50:05.00,Default,,0,0,0,,这就是
Dialogue: 0,0:50:05.52,0:50:06.97,Default,,0,0,0,,数据与过程之间
Dialogue: 0,0:50:06.99,0:50:08.44,Default,,0,0,0,,并没有绝对的界限
Dialogue: 0,0:50:09.24,0:50:10.54,Default,,0,0,0,,流会是这样的一种结构
Dialogue: 0,0:50:10.59,0:50:13.40,Default,,0,0,0,,它既是一种传统意义上的“数据结构”
Dialogue: 0,0:50:13.45,0:50:15.92,Default,,0,0,0,,比如树的叶子结点组成的流
Dialogue: 0,0:50:16.86,0:50:17.85,Default,,0,0,0,,但是同时
Dialogue: 0,0:50:17.85,0:50:19.32,Default,,0,0,0,,它又是一种非常聪明的过程
Dialogue: 0,0:50:20.24,0:50:22.22,Default,,0,0,0,,它包含了如何计算的方法
Dialogue: 0,0:50:23.74,0:50:25.93,Default,,0,0,0,,好吧 实际来看一下
Dialogue: 0,0:50:25.93,0:50:26.62,Default,,0,0,0,,事实上
Dialogue: 0,0:50:26.80,0:50:28.33,Default,,0,0,0,,我们不需要其它的机制
Dialogue: 0,0:50:28.46,0:50:29.87,Default,,0,0,0,,我们已经有了所需要的一切东西
Dialogue: 0,0:50:30.14,0:50:30.99,Default,,0,0,0,,这是因为
Dialogue: 0,0:50:31.02,0:50:33.93,Default,,0,0,0,,我们已经能够 把过程当作第一级对象来处理了
Dialogue: 0,0:50:35.46,0:50:36.88,Default,,0,0,0,,来看看这个关键之处
Dialogue: 0,0:50:36.88,0:50:39.03,Default,,0,0,0,,关键在于 -- 回想一下 我们有这些运算
Dialogue: 0,0:50:39.03,0:50:47.52,Default,,0,0,0,,CONS-STREAM、HEAD和TAIL
Dialogue: 0,0:50:48.08,0:50:49.36,Default,,0,0,0,,刚开始的时候我说
Dialogue: 0,0:50:49.92,0:50:51.36,Default,,0,0,0,,你们可以把这个看作CONS
Dialogue: 0,0:50:51.40,0:50:52.62,Default,,0,0,0,,把HEAD看作CAR
Dialogue: 0,0:50:52.62,0:50:53.52,Default,,0,0,0,,把TAIL看作CDR
Dialogue: 0,0:50:53.55,0:50:54.16,Default,,0,0,0,,事实上没这么简单
Dialogue: 0,0:50:55.08,0:50:56.32,Default,,0,0,0,,现在 来看看它们到底是什么
Dialogue: 0,0:50:57.71,0:51:05.84,Default,,0,0,0,,(CONS-STREAM X Y)
Dialogue: 0,0:51:07.48,0:51:17.79,Default,,0,0,0,,是这个东西的缩写形式
Dialogue: 0,0:51:19.54,0:51:28.32,Default,,0,0,0,,(CONS X (DELAY Y))
Dialogue: 0,0:51:31.68,0:51:33.53,Default,,0,0,0,,我先把它们写完再来解释
Dialogue: 0,0:51:34.52,0:51:35.53,Default,,0,0,0,,而(HEAD S)
Dialogue: 0,0:51:38.09,0:51:39.79,Default,,0,0,0,,就是 (CAR S)
Dialogue: 0,0:51:42.38,0:51:44.25,Default,,0,0,0,,而(TAIL S)
Dialogue: 0,0:51:46.68,0:51:54.60,Default,,0,0,0,,则是(FORCE (CDR S))
Dialogue: 0,0:51:56.12,0:51:57.04,Default,,0,0,0,,我来解释一下
Dialogue: 0,0:51:58.06,0:51:59.88,Default,,0,0,0,,DELAY是一个特殊而神奇的东西
Dialogue: 0,0:52:01.42,0:52:02.33,Default,,0,0,0,,DELAY所做是
Dialogue: 0,0:52:03.85,0:52:05.31,Default,,0,0,0,,取一个表达式
Dialogue: 0,0:52:05.50,0:52:06.86,Default,,0,0,0,,然后产生一个PROMISE
Dialogue: 0,0:52:07.12,0:52:09.15,Default,,0,0,0,,在你有需要时 这个PROMISE会计算那个表达式
Dialogue: 0,0:52:10.60,0:52:11.98,Default,,0,0,0,,但在此时没有做任何计算
Dialogue: 0,0:52:11.98,0:52:14.32,Default,,0,0,0,,只是一个延期的PROMISE
Dialogue: 0,0:52:14.82,0:52:16.20,Default,,0,0,0,,承诺要做这样的事
Dialogue: 0,0:52:17.11,0:52:18.20,Default,,0,0,0,,CONS-STREAM所做的就是
Dialogue: 0,0:52:18.81,0:52:21.96,Default,,0,0,0,,把X和一个计算Y的PROMISE
Dialogue: 0,0:52:23.31,0:52:25.36,Default,,0,0,0,,放在在一个序对里
Dialogue: 0,0:52:28.23,0:52:28.99,Default,,0,0,0,,如果我需要头部分
Dialogue: 0,0:52:28.99,0:52:30.75,Default,,0,0,0,,那么就是这个序对的CAR部分
Dialogue: 0,0:52:31.84,0:52:33.71,Default,,0,0,0,,关键在于 它的尾部分
Dialogue: 0,0:52:34.62,0:52:36.65,Default,,0,0,0,,强制会调用该PROMISE
Dialogue: 0,0:52:38.22,0:52:39.88,Default,,0,0,0,,而TAIL会说
Dialogue: 0,0:52:40.03,0:52:41.02,Default,,0,0,0,,好吧 取出该PROMISE
Dialogue: 0,0:52:41.85,0:52:44.52,Default,,0,0,0,,然后调用该PROMISE
Dialogue: 0,0:52:44.56,0:52:46.03,Default,,0,0,0,,这才开始实际的计算
Dialogue: 0,0:52:47.69,0:52:48.72,Default,,0,0,0,,这就是它的实际工作方式
Dialogue: 0,0:52:48.74,0:52:51.55,Default,,0,0,0,,这就是CONS-STREAM、HEAD和TAIL的真正定义
Dialogue: 0,0:52:54.60,0:52:55.57,Default,,0,0,0,,具体演示一下
Dialogue: 0,0:52:55.57,0:52:57.50,Default,,0,0,0,,我们小心翼翼地来审查一遍
Dialogue: 0,0:52:58.76,0:53:00.62,Default,,0,0,0,,现在从计算10,000到1,000,000中的
Dialogue: 0,0:53:01.32,0:53:03.66,Default,,0,0,0,,第二个质数这个实例来看
Dialogue: 0,0:53:05.50,0:53:07.16,Default,,0,0,0,,看看是怎么运行的
Dialogue: 0,0:53:08.65,0:53:12.03,Default,,0,0,0,,好的 我们从这个表达式开始
Dialogue: 0,0:53:15.36,0:53:16.62,Default,,0,0,0,,第二个质数就是
Dialogue: 0,0:53:16.64,0:53:21.90,Default,,0,0,0,,就是(HEAD (TAIL (FILTER PRIME? ... )))
Dialogue: 0,0:53:22.83,0:53:25.31,Default,,0,0,0,,枚举的范围是(E-I 10000 1000000)
Dialogue: 0,0:53:26.71,0:53:27.61,Default,,0,0,0,,这是什么呢?
Dialogue: 0,0:53:28.40,0:53:29.20,Default,,0,0,0,,那就是
Dialogue: 0,0:53:31.63,0:53:34.17,Default,,0,0,0,,枚举的这个10,000至1,000,000的区间
Dialogue: 0,0:53:35.72,0:53:37.32,Default,,0,0,0,,如果你追踪这个枚举区间
Dialogue: 0,0:53:37.34,0:53:38.78,Default,,0,0,0,,会发现它构造了一个流
Dialogue: 0,0:53:39.92,0:53:41.39,Default,,0,0,0,,CONS-STREAM实际代换过来是
Dialogue: 0,0:53:41.96,0:53:43.61,Default,,0,0,0,,把10,000
Dialogue: 0,0:53:44.51,0:53:48.92,Default,,0,0,0,,和一个计算10,001到1,000,000之间整数的PROMISE结合起来
Dialogue: 0,0:53:54.00,0:53:55.75,Default,,0,0,0,,这也就是上面这个表达式
Dialogue: 0,0:53:55.75,0:53:57.32,Default,,0,0,0,,现在我使用代换模型
Dialogue: 0,0:53:57.64,0:53:59.32,Default,,0,0,0,,我们可以用代换模型的原因是
Dialogue: 0,0:53:59.34,0:54:01.01,Default,,0,0,0,,这里并没有涉及状态和副作用
Dialogue: 0,0:54:03.56,0:54:06.38,Default,,0,0,0,,所以我有10,000
Dialogue: 0,0:54:06.41,0:54:08.27,Default,,0,0,0,,和一个计算剩余整数构成的流
Dialogue: 0,0:54:08.32,0:54:10.49,Default,,0,0,0,,而到现在为止 只有一个整数被枚举了出来
Dialogue: 0,0:54:14.38,0:54:16.96,Default,,0,0,0,,然后过滤函数会对它做素性测试
Dialogue: 0,0:54:19.44,0:54:21.90,Default,,0,0,0,,我们再来仔细看看过滤函数的代码
Dialogue: 0,0:54:22.36,0:54:24.46,Default,,0,0,0,,过滤函数首先测试流的首部分
Dialogue: 0,0:54:25.46,0:54:28.25,Default,,0,0,0,,这里 过滤函数会测试10,000
Dialogue: 0,0:54:30.30,0:54:32.97,Default,,0,0,0,,然后输出:10,000不是质数
Dialogue: 0,0:54:33.50,0:54:35.85,Default,,0,0,0,,因此我只需要
Dialogue: 0,0:54:36.25,0:54:37.39,Default,,0,0,0,,递归地过滤尾部分
Dialogue: 0,0:54:39.22,0:54:40.14,Default,,0,0,0,,尾部分是什么呢?
Dialogue: 0,0:54:40.16,0:54:43.76,Default,,0,0,0,,就是这个流的尾部分 -- 一个PROMISE
Dialogue: 0,0:54:46.34,0:54:48.06,Default,,0,0,0,,我们进入到尾部分
Dialogue: 0,0:54:48.28,0:54:49.50,Default,,0,0,0,,强制(计算)该PROMISE
Dialogue: 0,0:54:49.68,0:54:50.94,Default,,0,0,0,,我强制计算该PROMISE
Dialogue: 0,0:54:52.30,0:54:54.36,Default,,0,0,0,,这就意味着 我现在要
Dialogue: 0,0:54:55.58,0:54:57.96,Default,,0,0,0,,枚举10,001到1,000,000之间的整数
Dialogue: 0,0:55:00.80,0:55:02.97,Default,,0,0,0,,现在 过滤函数处理的是这个东西
Dialogue: 0,0:55:07.81,0:55:08.92,Default,,0,0,0,,这个枚举函数枚举了它自己
Dialogue: 0,0:55:08.94,0:55:11.23,Default,,0,0,0,,我们又回到了最初那种枚举情况
Dialogue: 0,0:55:11.96,0:55:13.00,Default,,0,0,0,,我们的枚举函数的
Dialogue: 0,0:55:14.12,0:55:16.44,Default,,0,0,0,,首部分是整数10,001
Dialogue: 0,0:55:16.60,0:55:18.20,Default,,0,0,0,,尾部分是计算剩余部分的PROMISE
Dialogue: 0,0:55:19.74,0:55:22.75,Default,,0,0,0,,因此现在素性过滤函数将会测试10,001
Dialogue: 0,0:55:23.23,0:55:25.12,Default,,0,0,0,,开始判断它是不是质数
Dialogue: 0,0:55:25.12,0:55:27.08,Default,,0,0,0,,结果10,001不是质数
Dialogue: 0,0:55:27.55,0:55:29.61,Default,,0,0,0,,然后再不断地强制求值PROMISE
Dialogue: 0,0:55:32.92,0:55:35.80,Default,,0,0,0,,最后 我觉得它找到的第一个质数可能是10,009
Dialogue: 0,0:55:37.10,0:55:38.33,Default,,0,0,0,,它会在这个时候停止
Dialogue: 0,0:55:40.84,0:55:41.93,Default,,0,0,0,,这只是第一个质数
Dialogue: 0,0:55:41.96,0:55:43.48,Default,,0,0,0,,然而 我们需要的是第二个
Dialogue: 0,0:55:45.24,0:55:46.84,Default,,0,0,0,,所以 这时它又启动了
Dialogue: 0,0:55:47.03,0:55:48.25,Default,,0,0,0,,你会发现
Dialogue: 0,0:55:48.52,0:55:50.49,Default,,0,0,0,,你需要多少
Dialogue: 0,0:55:51.85,0:55:52.91,Default,,0,0,0,,它就只会生成多少
Dialogue: 0,0:55:56.48,0:55:59.92,Default,,0,0,0,,枚举函数生成整数的数量
Dialogue: 0,0:56:00.12,0:56:01.45,Default,,0,0,0,,不会比过滤函数所要求的多
Dialogue: 0,0:56:01.47,0:56:03.45,Default,,0,0,0,,因为它只是取一部分数来做素性测试
Dialogue: 0,0:56:04.70,0:56:06.51,Default,,0,0,0,,过滤函数也不会生成
Dialogue: 0,0:56:06.54,0:56:08.04,Default,,0,0,0,,比你的要求更多的东西
Dialogue: 0,0:56:08.06,0:56:09.10,Default,,0,0,0,,也就是尾部分的首部分
Dialogue: 0,0:56:11.61,0:56:13.26,Default,,0,0,0,,你们看
Dialogue: 0,0:56:14.70,0:56:18.24,Default,,0,0,0,,我们把计算机运行中实际进行的
Dialogue: 0,0:56:18.67,0:56:20.65,Default,,0,0,0,,生成与测试的过程 混合在了一起
Dialogue: 0,0:56:21.52,0:56:22.67,Default,,0,0,0,,尽管
Dialogue: 0,0:56:23.18,0:56:25.63,Default,,0,0,0,,我们的程序“看起来”显然不是这样
Dialogue: 0,0:56:28.12,0:56:29.40,Default,,0,0,0,,看起来都很简单
Dialogue: 0,0:56:30.23,0:56:32.67,Default,,0,0,0,,这种机制的神奇之处在于DELAY
Dialogue: 0,0:56:33.68,0:56:35.66,Default,,0,0,0,,所以你也许会说 这全是因为DELAY很强大
Dialogue: 0,0:56:36.90,0:56:38.57,Default,,0,0,0,,但其实并不是
Dialogue: 0,0:56:39.07,0:56:39.98,Default,,0,0,0,,DELAY其实很简单
Dialogue: 0,0:56:40.61,0:56:45.07,Default,,0,0,0,,(DELAY <EXP>)
Dialogue: 0,0:56:48.25,0:56:50.04,Default,,0,0,0,,只是一个缩略表达
Dialogue: 0,0:56:53.36,0:56:55.63,Default,,0,0,0,,它是-- 创建一个用于计算表达式的PROMISE
Dialogue: 0,0:56:56.49,0:57:01.12,Default,,0,0,0,,(LAMBDA () <EXP>) 这样的一个表达式
Dialogue: 0,0:57:02.83,0:57:03.84,Default,,0,0,0,,这就是整个过程
Dialogue: 0,0:57:03.98,0:57:05.53,Default,,0,0,0,,这个PROMISE将要计算表达式<EXP>
Dialogue: 0,0:57:06.05,0:57:06.73,Default,,0,0,0,,FORCE过程又是什么?
Dialogue: 0,0:57:07.34,0:57:10.80,Default,,0,0,0,,如何处理这个PROMISE
Dialogue: 0,0:57:10.80,0:57:14.11,Default,,0,0,0,,FROCE一个PROMISE -- 也就是某个过程
Dialogue: 0,0:57:14.78,0:57:15.40,Default,,0,0,0,,只是简单地运行它
Dialogue: 0,0:57:19.23,0:57:19.56,Default,,0,0,0,,就是这样
Dialogue: 0,0:57:20.24,0:57:21.37,Default,,0,0,0,,所以这里并没有什么魔法
Dialogue: 0,0:57:23.52,0:57:24.24,Default,,0,0,0,,总结一下 我们都干了些什么?
Dialogue: 0,0:57:26.44,0:57:27.50,Default,,0,0,0,,我们说
Dialogue: 0,0:57:28.14,0:57:30.81,Default,,0,0,0,,传统的编程方式更有效
Dialogue: 0,0:57:30.96,0:57:33.92,Default,,0,0,0,,而流程序却更加清晰
Dialogue: 0,0:57:35.50,0:57:38.72,Default,,0,0,0,,我们设法用DELAY
Dialogue: 0,0:57:38.81,0:57:43.23,Default,,0,0,0,,使流程序和其它过程一样高效
Dialogue: 0,0:57:43.35,0:57:46.43,Default,,0,0,0,,DELAY所做的就是把
Dialogue: 0,0:57:46.68,0:57:50.40,Default,,0,0,0,,我们程序中 事件发生的逻辑顺序
Dialogue: 0,0:57:51.21,0:57:53.84,Default,,0,0,0,,和机器中 事件发生的实际顺序 解耦开来
Dialogue: 0,0:57:54.44,0:57:55.93,Default,,0,0,0,,这是DELAY的实质作用
Dialogue: 0,0:57:57.15,0:57:58.29,Default,,0,0,0,,也是全部的重点
Dialogue: 0,0:57:58.29,0:58:01.92,Default,,0,0,0,,我们放弃了那种想法
Dialogue: 0,0:58:02.30,0:58:04.17,Default,,0,0,0,,即程序的运行
Dialogue: 0,0:58:04.67,0:58:05.95,Default,,0,0,0,,或者源码的编排
Dialogue: 0,0:58:06.33,0:58:08.25,Default,,0,0,0,,反映了时间的明确概念
Dialogue: 0,0:58:09.45,0:58:10.57,Default,,0,0,0,,一旦放弃了这种想法
Dialogue: 0,0:58:11.21,0:58:13.32,Default,,0,0,0,,我们能使用DELAY
Dialogue: 0,0:58:13.34,0:58:15.20,Default,,0,0,0,,自由地安排计算顺序
Dialogue: 0,0:58:16.69,0:58:17.61,Default,,0,0,0,,整个思想就是这样
Dialogue: 0,0:58:17.61,0:58:19.45,Default,,0,0,0,,我们解耦了
Dialogue: 0,0:58:19.95,0:58:21.13,Default,,0,0,0,,程序的逻辑顺序
Dialogue: 0,0:58:21.16,0:58:22.89,Default,,0,0,0,,和其实际运行的顺序
Dialogue: 0,0:58:24.09,0:58:25.77,Default,,0,0,0,,对了 还有一个细节
Dialogue: 0,0:58:25.77,0:58:27.21,Default,,0,0,0,,一个技术性的细节
Dialogue: 0,0:58:27.21,0:58:28.43,Default,,0,0,0,,但是也非常重要
Dialogue: 0,0:58:29.73,0:58:32.01,Default,,0,0,0,,当你们运行这些递归程序的时候
Dialogue: 0,0:58:32.16,0:58:33.58,Default,,0,0,0,,你会看到很多像是
Dialogue: 0,0:58:33.64,0:58:37.87,Default,,0,0,0,,(TAIL (TAIL (TAIL ... 这样的东西
Dialogue: 0,0:58:39.20,0:58:41.02,Default,,0,0,0,,如果流是通过嵌套的CONS构造起来的
Dialogue: 0,0:58:41.02,0:58:42.88,Default,,0,0,0,,就会出现这种情况
Dialogue: 0,0:58:43.86,0:58:46.09,Default,,0,0,0,,如果我每次都要执行一次
Dialogue: 0,0:58:46.14,0:58:47.58,Default,,0,0,0,,如果我每次都要计算TAIL
Dialogue: 0,0:58:48.22,0:58:50.88,Default,,0,0,0,,我对一个过程求值
Dialogue: 0,0:58:51.07,0:58:53.07,Default,,0,0,0,,这个过程又将重新计算它的TAIL
Dialogue: 0,0:58:53.10,0:58:55.40,Default,,0,0,0,,它的TAIL又将重新计算TAIL的TAIL
Dialogue: 0,0:58:55.50,0:58:56.88,Default,,0,0,0,,你们可以发现这非常低效
Dialogue: 0,0:58:57.77,0:59:00.56,Default,,0,0,0,,尤其是跟已经存放了所有元素的表相比
Dialogue: 0,0:59:01.16,0:59:04.00,Default,,0,0,0,,因为那样 在取得下一个TAIL的时候不需要重新计算
Dialogue: 0,0:59:05.29,0:59:08.28,Default,,0,0,0,,因此 这里有一个小技巧
Dialogue: 0,0:59:09.66,0:59:13.13,Default,,0,0,0,,通过稍微修改DELAY的定义
Dialogue: 0,0:59:14.96,0:59:18.20,Default,,0,0,0,,就可以让整件事变得 -- 我先写一下
Dialogue: 0,0:59:19.68,0:59:22.04,Default,,0,0,0,,DELAY实际的实现是
Dialogue: 0,0:59:24.52,0:59:27.93,Default,,0,0,0,,(DELAY <exp>)是这样一个表达式的简写
Dialogue: 0,0:59:28.11,0:59:30.86,Default,,0,0,0,,(MEMO-PROC (LAMBDA () <EXP>))
Dialogue: 0,0:59:31.00,0:59:34.06,Default,,0,0,0,,MEMO-PROC是一个可以改变过程的特殊过程
Dialogue: 0,0:59:35.15,0:59:37.80,Default,,0,0,0,,它接受一个无参过程
Dialogue: 0,0:59:39.02,0:59:41.05,Default,,0,0,0,,并把该过程变为
Dialogue: 0,0:59:41.36,0:59:43.55,Default,,0,0,0,,只需要执行一次计算的过程
Dialogue: 0,0:59:45.10,0:59:47.45,Default,,0,0,0,,我们意思是 你给它一个过程
Dialogue: 0,0:59:48.70,0:59:50.86,Default,,0,0,0,,MEMO-PROC返回一个新的过程
Dialogue: 0,0:59:51.39,0:59:53.00,Default,,0,0,0,,当你首次调用这个新过程
Dialogue: 0,0:59:53.71,0:59:55.07,Default,,0,0,0,,它会运行原始过程
Dialogue: 0,0:59:55.31,0:59:56.91,Default,,0,0,0,,并记下结果
Dialogue: 0,0:59:58.56,1:00:00.68,Default,,0,0,0,,从那之后 每次你再运行这个过程
Dialogue: 0,1:00:00.68,1:00:02.17,Default,,0,0,0,,就不用再计算了
Dialogue: 0,1:00:02.19,1:00:04.43,Default,,0,0,0,,它会把结果存储在一个地方
Dialogue: 0,1:00:05.20,1:00:06.92,Default,,0,0,0,,可以这样来实现MEMO-PROC
Dialogue: 0,1:00:11.21,1:00:12.71,Default,,0,0,0,,一旦你了解怎么做 实现就很容易了
Dialogue: 0,1:00:12.71,1:00:16.76,Default,,0,0,0,,MEMO-PROC中有两个标记变量
Dialogue: 0,1:00:17.39,1:00:19.20,Default,,0,0,0,,ALREADY-RUN?用于记录是否运行过
Dialogue: 0,1:00:20.32,1:00:22.48,Default,,0,0,0,,初始值是NIL 指示没运行过
Dialogue: 0,1:00:23.62,1:00:27.04,Default,,0,0,0,,RESULT用于存储上一次计算的结果
Dialogue: 0,1:00:29.07,1:00:31.07,Default,,0,0,0,,MEMO-PROC接收一个过程PROC
Dialogue: 0,1:00:31.56,1:00:34.01,Default,,0,0,0,,返回一个新的无参过程
Dialogue: 0,1:00:34.36,1:00:36.38,Default,,0,0,0,,PROC也是一个无参过程
Dialogue: 0,1:00:38.61,1:00:41.37,Default,,0,0,0,,它会判断 -- 如果没有运行过
Dialogue: 0,1:00:42.59,1:00:44.06,Default,,0,0,0,,就进行一系列的运算
Dialogue: 0,1:00:44.43,1:00:46.56,Default,,0,0,0,,先计算PROC
Dialogue: 0,1:00:47.50,1:00:48.45,Default,,0,0,0,,然后存储它的值
Dialogue: 0,1:00:48.45,1:00:50.48,Default,,0,0,0,,存储在变量RESULT中
Dialogue: 0,1:00:51.14,1:00:53.90,Default,,0,0,0,,然后对ALREADY-RUN?赋值 提醒自己已经运行过了
Dialogue: 0,1:00:54.28,1:00:55.47,Default,,0,0,0,,最后返回RESULT
Dialogue: 0,1:00:56.61,1:00:59.01,Default,,0,0,0,,所以之前如果没运行过 就执行一次计算
Dialogue: 0,1:00:59.01,1:01:01.88,Default,,0,0,0,,当你调用它 但已经运行过了 就直接返回结果
Dialogue: 0,1:01:03.42,1:01:07.12,Default,,0,0,0,,这种聪明的小技巧被称作“记忆化”
Dialogue: 0,1:01:08.40,1:01:09.13,Default,,0,0,0,,这样的话
Dialogue: 0,1:01:10.35,1:01:14.14,Default,,0,0,0,,就不会重复的计算TAIL了
Dialogue: 0,1:01:15.27,1:01:17.81,Default,,0,0,0,,不再那样的没效率了
Dialogue: 0,1:01:17.81,1:01:18.72,Default,,0,0,0,,事实上 流式程序设计
Dialogue: 0,1:01:19.20,1:01:22.75,Default,,0,0,0,,甚至和传统的那种程序一样有效
Dialogue: 0,1:01:24.01,1:01:26.20,Default,,0,0,0,,再强调一下 整个的思想在于
Dialogue: 0,1:01:27.48,1:01:28.60,Default,,0,0,0,,我们已经讲过
Dialogue: 0,1:01:29.26,1:01:32.40,Default,,0,0,0,,过程与数据之间
Dialogue: 0,1:01:32.41,1:01:33.61,Default,,0,0,0,,没有一个明确的分界线
Dialogue: 0,1:01:33.61,1:01:35.61,Default,,0,0,0,,事实上 我们把数据结构组织得
Dialogue: 0,1:01:36.00,1:01:37.31,Default,,0,0,0,,像一个过程
Dialogue: 0,1:01:38.76,1:01:40.73,Default,,0,0,0,,它使得我们能够
Dialogue: 0,1:01:41.58,1:01:46.54,Default,,0,0,0,,可以实现一种常见的控制结构
Dialogue: 0,1:01:46.68,1:01:48.91,Default,,0,0,0,,在本例中是迭代
Dialogue: 0,1:01:49.62,1:01:51.05,Default,,0,0,0,,我们创建了一种数据结构
Dialogue: 0,1:01:51.32,1:01:52.84,Default,,0,0,0,,由于这种数据结构本身是一个过程
Dialogue: 0,1:01:52.86,1:01:55.12,Default,,0,0,0,,它其中就可以有某种控制结构
Dialogue: 0,1:01:55.79,1:01:57.13,Default,,0,0,0,,这就是流的实质
Dialogue: 0,1:01:58.91,1:01:59.76,Default,,0,0,0,,好 大家有什么问题吗?
Dialogue: 0,1:02:03.95,1:02:05.84,Default,,0,0,0,,学生:你刚才说(TAIL (TAIL (TAIL ...
Dialogue: 0,1:02:05.85,1:02:07.16,Default,,0,0,0,,如果我没理解错的话
Dialogue: 0,1:02:07.28,1:02:10.76,Default,,0,0,0,,没有没有MEMO-PROC的话
Dialogue: 0,1:02:10.78,1:02:12.83,Default,,0,0,0,,FORCE实际上执行了一个过程
Dialogue: 0,1:02:12.89,1:02:13.15,Default,,0,0,0,,教授:是的
Dialogue: 0,1:02:13.44,1:02:16.38,Default,,0,0,0,,学生:你说使用那个MEMO-PROC就不会有那样的问题
Dialogue: 0,1:02:16.38,1:02:18.73,Default,,0,0,0,,这难道不需要保证
Dialogue: 0,1:02:19.34,1:02:22.19,Default,,0,0,0,,(TAIL (TAIL (TAIL 每次的计算结构都是一致的么?
Dialogue: 0,1:02:22.41,1:02:23.91,Default,,0,0,0,,教授:哦 当然
Dialogue: 0,1:02:23.91,1:02:25.84,Default,,0,0,0,,学生:我可能是漏了什么知识点
Dialogue: 0,1:02:26.05,1:02:27.21,Default,,0,0,0,,教授:你说得很对 这里 --
Dialogue: 0,1:02:31.12,1:02:33.64,Default,,0,0,0,,首先 为了获得结果需要进行一次计算
Dialogue: 0,1:02:34.09,1:02:36.76,Default,,0,0,0,,关键在于 一旦得到 (TAIL STREAM)
Dialogue: 0,1:02:37.58,1:02:38.70,Default,,0,0,0,,再计算 (TAIL (TAIL STREAM)) 的时候
Dialogue: 0,1:02:38.70,1:02:40.51,Default,,0,0,0,,就不用再计算最内部的TAIL了
Dialogue: 0,1:02:42.98,1:02:44.32,Default,,0,0,0,,明白了吧 如果我没有用MEMO-PROC
Dialogue: 0,1:02:44.35,1:02:46.09,Default,,0,0,0,,还要再计算一遍 (TAIL STREAM)
Dialogue: 0,1:02:46.46,1:02:47.13,Default,,0,0,0,,学生:明白了
Dialogue: 0,1:02:50.83,1:02:52.56,Default,,0,0,0,,学生:之前的例子中你提到过
Dialogue: 0,1:02:52.60,1:02:54.22,Default,,0,0,0,,我们之所以可以使用代换模型
Dialogue: 0,1:02:54.22,1:02:56.11,Default,,0,0,0,,是因为这里没有副作用
Dialogue: 0,1:02:56.83,1:03:00.73,Default,,0,0,0,,如果我们的信号处理单元
Dialogue: 0,1:03:00.78,1:03:02.03,Default,,0,0,0,,具有副作用
Dialogue: 0,1:03:02.04,1:03:03.04,Default,,0,0,0,,具有内部状态
Dialogue: 0,1:03:03.62,1:03:06.84,Default,,0,0,0,,我们还有效地构建流模型么?
Dialogue: 0,1:03:08.46,1:03:10.59,Default,,0,0,0,,教授:可能吧 这是一个很困难的问题
Dialogue: 0,1:03:11.20,1:03:13.42,Default,,0,0,0,,关于代换模型和副作用并不是很兼容这一点
Dialogue: 0,1:03:14.36,1:03:18.24,Default,,0,0,0,,我以后会稍稍地讲解一下
Dialogue: 0,1:03:18.96,1:03:20.48,Default,,0,0,0,,但大体来说 我认为
Dialogue: 0,1:03:20.49,1:03:21.63,Default,,0,0,0,,除非你非常小心
Dialogue: 0,1:03:21.90,1:03:24.46,Default,,0,0,0,,否则副作用会把一切弄得很糟糕
Dialogue: 0,1:03:35.04,1:03:38.25,Default,,0,0,0,,学生:我不是很理解MEMO-PROC这个过程
Dialogue: 0,1:03:39.68,1:03:41.12,Default,,0,0,0,,你是什么时候执行那个LAMBDA的?
Dialogue: 0,1:03:41.99,1:03:43.21,Default,,0,0,0,,换句话说
Dialogue: 0,1:03:43.68,1:03:45.15,Default,,0,0,0,,当MEMO-PROC执行的时候
Dialogue: 0,1:03:45.18,1:03:47.71,Default,,0,0,0,,只生成了LAMBDA表达式
Dialogue: 0,1:03:48.01,1:03:49.68,Default,,0,0,0,,但我不太清楚它是什么时候被执行的
Dialogue: 0,1:03:50.39,1:03:51.12,Default,,0,0,0,,教授:好的
Dialogue: 0,1:03:51.35,1:03:52.68,Default,,0,0,0,,MEMO-PROC所做的 --
Dialogue: 0,1:03:53.07,1:03:55.85,Default,,0,0,0,,MEMO-PROC的一个参数是PROC
Dialogue: 0,1:03:56.38,1:03:57.93,Default,,0,0,0,,一个没有参数的过程
Dialogue: 0,1:03:57.93,1:03:59.05,Default,,0,0,0,,某个时刻 你会调用它
Dialogue: 0,1:04:00.39,1:04:02.75,Default,,0,0,0,,MEMO-PROC把该过程转化为
Dialogue: 0,1:04:02.75,1:04:04.56,Default,,0,0,0,,另一个无参过程
Dialogue: 0,1:04:04.59,1:04:05.80,Default,,0,0,0,,某个时刻你会调用到它
Dialogue: 0,1:04:06.62,1:04:07.42,Default,,0,0,0,,LAMBDA语句做的是这个
Dialogue: 0,1:04:09.89,1:04:14.08,Default,,0,0,0,,所以在这里 我最初构造
Dialogue: 0,1:04:15.85,1:04:17.92,Default,,0,0,0,,构造流的TAIL的时候
Dialogue: 0,1:04:18.30,1:04:20.48,Default,,0,0,0,,这里的这个无参过程
Dialogue: 0,1:04:20.51,1:04:21.61,Default,,0,0,0,,会在之后的某个时刻调用
Dialogue: 0,1:04:24.10,1:04:28.01,Default,,0,0,0,,相对应的 我要对(TAIL STREAM)调用MEMO-PROC
Dialogue: 0,1:04:28.12,1:04:29.24,Default,,0,0,0,,以后我会调用生成的过程
Dialogue: 0,1:04:30.65,1:04:31.90,Default,,0,0,0,,所以这个无参的LAMBDA
Dialogue: 0,1:04:32.03,1:04:36.06,Default,,0,0,0,,是当你在调用MEMO-PROC时调用的
Dialogue: 0,1:04:38.97,1:04:40.96,Default,,0,0,0,,当你调用MEMP-PROC返回的过程时
Dialogue: 0,1:04:40.97,1:04:42.28,Default,,0,0,0,,也就会像通常的过程调用那样
Dialogue: 0,1:04:42.36,1:04:45.76,Default,,0,0,0,,调用你最初设定的那个函数
Dialogue: 0,1:04:47.64,1:04:48.86,Default,,0,0,0,,学生:我想问的是
Dialogue: 0,1:04:48.86,1:04:50.86,Default,,0,0,0,,当你调用MEMO-PROC的时候
Dialogue: 0,1:04:50.86,1:04:52.30,Default,,0,0,0,,你返回了这个LAMBDA
Dialogue: 0,1:04:52.61,1:04:53.07,Default,,0,0,0,,教授:是的
Dialogue: 0,1:04:53.77,1:04:58.10,Default,,0,0,0,,你调用MEMO-PROC的时候 返回了一个LAMBDA
Dialogue: 0,1:04:58.10,1:04:59.84,Default,,0,0,0,,直到你第一次需要执行它的时候
Dialogue: 0,1:04:59.87,1:05:02.27,Default,,0,0,0,,你才去求值<EXP>
Dialogue: 0,1:05:07.76,1:05:09.10,Default,,0,0,0,,学生:我这样理解对吗?
Dialogue: 0,1:05:09.18,1:05:11.40,Default,,0,0,0,,你构造了一个表
Dialogue: 0,1:05:11.47,1:05:14.17,Default,,0,0,0,,但表中的元素还没有被求值
Dialogue: 0,1:05:14.24,1:05:15.63,Default,,0,0,0,,表达式没有被求值?
Dialogue: 0,1:05:15.63,1:05:18.54,Default,,0,0,0,,但在每个阶段 你还是构造了一个表
Dialogue: 0,1:05:18.54,1:05:20.70,Default,,0,0,0,,教授:啊 我应该这样说
Dialogue: 0,1:05:20.70,1:05:22.27,Default,,0,0,0,,这个想法很好
Dialogue: 0,1:05:22.27,1:05:23.18,Default,,0,0,0,,但是 也不全对
Dialogue: 0,1:05:23.66,1:05:25.08,Default,,0,0,0,,因为实际发生的事情是这样的
Dialogue: 0,1:05:25.08,1:05:26.35,Default,,0,0,0,,我先把这个画成序对
Dialogue: 0,1:05:26.89,1:05:28.03,Default,,0,0,0,,假设我要构造一个特别大的流
Dialogue: 0,1:05:28.96,1:05:30.12,Default,,0,0,0,,比如枚举一段区间
Dialogue: 0,1:05:30.32,1:05:31.48,Default,,0,0,0,,从1到1,000,000,000
Dialogue: 0,1:05:32.74,1:05:35.74,Default,,0,0,0,,这实际上是一个序对
Dialogue: 0,1:05:39.34,1:05:43.36,Default,,0,0,0,,由1和一个PROMISE组成
Dialogue: 0,1:05:46.73,1:05:47.89,Default,,0,0,0,,就是这样
Dialogue: 0,1:05:47.89,1:05:48.76,Default,,0,0,0,,什么都没有构造
Dialogue: 0,1:05:51.60,1:05:53.29,Default,,0,0,0,,当我继续FORCE这个PROMISE
Dialogue: 0,1:05:54.51,1:05:56.37,Default,,0,0,0,,再来看看 会发生什么
Dialogue: 0,1:05:56.37,1:05:59.66,Default,,0,0,0,,这个东西现在就成为了一个递归CONS
Dialogue: 0,1:06:00.53,1:06:02.16,Default,,0,0,0,,所以这个PROMISE现在就变成了
Dialogue: 0,1:06:04.62,1:06:08.96,Default,,0,0,0,,一个2和做更多事情的PROMISE
Dialogue: 0,1:06:11.35,1:06:12.73,Default,,0,0,0,,一直这样下去
Dialogue: 0,1:06:14.47,1:06:17.63,Default,,0,0,0,,直到你走完整个流才完整地构建了一个表
Dialogue: 0,1:06:18.20,1:06:19.58,Default,,0,0,0,,因为这个东西不是表
Dialogue: 0,1:06:20.03,1:06:21.48,Default,,0,0,0,,只是一个生成表的PROMISE
Dialogue: 0,1:06:23.39,1:06:25.50,Default,,0,0,0,,技术上来说 PROMISE就是一个过程
Dialogue: 0,1:06:27.80,1:06:29.10,Default,,0,0,0,,因此并没有直接构造好一个表
Dialogue: 0,1:06:30.76,1:06:32.72,Default,,0,0,0,,我应该早点说的
Dialogue: 0,1:06:34.28,1:06:35.34,Default,,0,0,0,,好吧 就到这里 下课
Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu
Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。