MIT OpenCourseWare
http://ocw.mit.edu


6.001 Structure and Interpretation of Computer Programs, Spring 2005

Transcript – 6A: Streams, Part 1



1
00:00:00,000 --> 00:00:18,550

2
00:00:18,550 --> 00:00:21,230
教授：好的，上次Gerry教授揭晓了秘密。
PROFESSOR: Well, last time Gerry
really let the cat out

3
00:00:21,230 --> 00:00:22,230
of the bag.

4
00:00:22,230 --> 00:00:26,350
他介绍赋值这个概念。
He introduced the idea
of assignment.

5
00:00:26,350 --> 00:00:33,405
赋值和状态。
Assignment and state.

6
00:00:33,405 --> 00:00:37,620

7
00:00:37,620 --> 00:00:41,500
就像我们看到的那样,把赋值和状态介绍
And as we started to see, the
implications of introducing

8
00:00:41,500 --> 00:00:43,860
进语言的含义是绝对惊世骇俗的
assignment and state into the
language are absolutely

9
00:00:43,860 --> 00:00:45,350
frightening.

10
00:00:45,350 --> 00:00:47,240
首先，计算的替换模型无法工作
First of all, the substitution
model of

11
00:00:47,240 --> 00:00:48,865
evaluation breaks down.

12
00:00:48,865 --> 00:00:52,210
我们就不得不使用更加复杂的环境模型
And we have to use this much
more complicated environment

13
00:00:52,210 --> 00:00:53,780
和这种带图解的机械化东西
model and this very mechanistic
thing with

14
00:00:53,780 --> 00:00:56,530
甚至说明了声明在编程语言中的意思
diagrams, even to say what
statements in the programming

15
00:00:56,530 --> 00:00:58,130
language mean.

16
00:00:58,130 --> 00:01:00,260
那不仅仅是技术上的一点
And that's not a mere
technical point.

17
00:01:00,260 --> 00:01:03,090
看 我们没有这样特定的替换模型
See, it's not that we had this
particular substitution model

18
00:01:03,090 --> 00:01:05,200
并且 这不能完全工作
and, well, it doesn't quite
work, so we have to do

19
00:01:05,200 --> 00:01:05,870
所以我们不得不做些别的
something else.

20
00:01:05,870 --> 00:01:10,730
替换模型啥都不能做
It's that nothing like the
substitution model can work.

21
00:01:10,730 --> 00:01:15,950
因为突然地，一个变量无法代表一个值
Because suddenly, a variable
is not just something that

22
00:01:15,950 --> 00:01:18,080
stands for a value.

23
00:01:18,080 --> 00:01:22,390
一个变量现在不得不以某种方法来指定一个位置来存放一个值
A variable now has to somehow
specify a place

24
00:01:22,390 --> 00:01:23,630
that holds a value.

25
00:01:23,630 --> 00:01:25,885
在那个地方的值可以改变
And the value that's in
that place can change.

26
00:01:25,885 --> 00:01:30,280

27
00:01:30,280 --> 00:01:39,110
或者举个例子，，一个类似fx的表达式可能有副作用
Or for instance, an expression
like f of x might have a side

28
00:01:39,110 --> 00:01:40,410
effect in it.

29
00:01:40,410 --> 00:01:44,160
所以如果我们说f（x）可以得到某些值
So if we say f of x and it has
some value, and then later we

30
00:01:44,160 --> 00:01:48,890
那么然后 我们再求一次f（x）可能会得到一个取决于顺序的不同结果
say f of x again, we might
get a different value

31
00:01:48,890 --> 00:01:49,730
depending on the order.

32
00:01:49,730 --> 00:01:52,780
所以 突然地 我们不但需要想到值，还要想的时间
So suddenly, we have to think
not only about values but

33
00:01:52,780 --> 00:01:54,030
about time.

34
00:01:54,030 --> 00:01:57,970

35
00:01:57,970 --> 00:02:02,070
并且 像序对这样的东西，已经不再是它们的cars
And then things like pairs are
no longer just their CARs and

36
00:02:02,070 --> 00:02:02,520
和cdrs了
their CDRs.

37
00:02:02,520 --> 00:02:06,310
一个序对现在不仅仅是它的car和cdr了
A pair now is not quite its CAR
and its CDR. It's rather

38
00:02:06,310 --> 00:02:08,449
而是它的“同一”
its identity.

39
00:02:08,449 --> 00:02:11,650
所以一个序对有“同一”
So a pair has identity.

40
00:02:11,650 --> 00:02:12,900
这是一个对象
It's an object.

41
00:02:12,900 --> 00:02:21,330

42
00:02:21,330 --> 00:02:26,280
两个有相同car和cdr的序列可能相同或不同
And two pairs that have the same
CAR and CDR might be the

43
00:02:26,280 --> 00:02:29,650
因为 突然地 我们不得不担心“共享”
same or different, because
suddenly we have to worry

44
00:02:29,650 --> 00:02:30,900
about sharing.

45
00:02:30,900 --> 00:02:34,960

46
00:02:34,960 --> 00:02:38,910
所以所有的这些东西和赋值一起被介绍
So all of these things enter
as soon as we introduce

47
00:02:38,910 --> 00:02:40,480
assignment.

48
00:02:40,480 --> 00:02:43,340
这和我们说代换的时候差别悬殊
See, this is a really far cry
from where we started with

49
00:02:43,340 --> 00:02:45,400
substitution.

50
00:02:45,400 --> 00:02:50,420
这是在技术上更加困难的一种看待事情的方法
It's a technically harder way
of looking at things because

51
00:02:50,420 --> 00:02:52,710
因为 我们不得不更加机械地思考我们的程序语言
we have to think more
mechanistically about our

52
00:02:52,710 --> 00:02:53,540
programming language.

53
00:02:53,540 --> 00:02:55,960
我们不能仅仅的用数学来思考它。
We can't just think about
it as mathematics.

54
00:02:55,960 --> 00:02:59,860
这在哲学上更加困难  因为突然 这里会出现一些
It's philosophically harder,
because suddenly there are all

55
00:02:59,860 --> 00:03:02,020
搞笑的问题 关于一些东西改变或者这两个东西是一样的是什么意思
these funny issues about what
does it mean that something

56
00:03:02,020 --> 00:03:04,050
changes or that two things
are the same.

57
00:03:04,050 --> 00:03:07,910
并且 这在编程上更加困难
And also, it's programming
harder, because as Gerry

58
00:03:07,910 --> 00:03:10,070
因为就像Gerry上次展示的那样
showed last time, there are all
these bugs having to do

59
00:03:10,070 --> 00:03:14,420
在一种我们不用担心对象的语言中不存在 那些由别名和坏的顺序造成的bugs
with bad sequencing and aliasing
that just don't exist

60
00:03:14,420 --> 00:03:18,210

in a language where we don't
worry about objects.

61
00:03:18,210 --> 00:03:23,635
我们是怎样陷入这样的困境呢
Well, how'd we get
into this mess?

62
00:03:23,635 --> 00:03:27,500
记住我们以前做的 我们陷入困境的原因是
Remember what we did, the reason
we got into this is

63
00:03:27,500 --> 00:03:35,750
因为我们想要去建造模块化的系统
because we were looking to
build modular systems. We

64
00:03:35,750 --> 00:03:40,250
我们想要建造一个看起来自然崩碎的数据块
wanted to build systems that
fall apart into chunks that

65
00:03:40,250 --> 00:03:42,760
seem natural.

66
00:03:42,760 --> 00:03:46,260
举个例子 我们想要拿一个随机数生成器
So for instance, we want to take
a random number generator

67
00:03:46,260 --> 00:03:48,660
并打包那个随机数生成器的状态
and package up the state of that
random number generator

68
00:03:48,660 --> 00:03:52,840
我们可以把用蒙特卡罗方法生成随机数
inside of it so that we can
separate the idea of picking

69
00:03:52,840 --> 00:03:56,640
的计算过程和随机数按照
random numbers from the general
Monte Carlo strategy

70
00:03:56,640 --> 00:03:59,740
cesaro的公式计算pi的计算过程分离开
of estimating something and
separate that from the

71
00:03:59,740 --> 00:04:03,060
particular way that you work
with random numbers in that

72
00:04:03,060 --> 00:04:06,980
formula developed by
Cesaro for pi.

73
00:04:06,980 --> 00:04:11,400
相似的 当我们动身去构建一些东西的模型
And similarly, when we go off
and construct some models of

74
00:04:11,400 --> 00:04:15,440
如果我们动身去构建一个我们在现实看到的系统模型
things, if we go off and model
a system that we see in the

75
00:04:15,440 --> 00:04:19,050
我们想要把我们的程序分散为自然的元件
real world, we'd like our
program to break into natural

76
00:04:19,050 --> 00:04:22,310
来反映我们在真实世界看到的系统的部分
pieces, pieces that mirror the
parts of the system that we

77
00:04:22,310 --> 00:04:24,900
see in the real world.

78
00:04:24,900 --> 00:04:28,780
所以举一个例子 如果我们看一下这个电子电路
So for example, if we look at
a digital circuit, we say,

79
00:04:28,780 --> 00:04:33,910
我们可以说 挖 这里有一个电路 它这里有一个元件
gee, there's a circuit and
it has a piece and

80
00:04:33,910 --> 00:04:35,160
并且那里还有一个另一个元件
it has another piece.

81
00:04:35,160 --> 00:04:40,100

82
00:04:40,100 --> 00:04:43,580
这些不同的元件在某种程度上有“同一”
And these different pieces
sort of have identity.

83
00:04:43,580 --> 00:04:45,550
它们有状态
They have state.

84
00:04:45,550 --> 00:04:48,580
状态附在电线上
And the state sits
on these wires.

85
00:04:48,580 --> 00:04:51,020
我们把这个元件看成一个不同于其他对象的对象
And we think of this piece as
an object that's different

86
00:04:51,020 --> 00:04:52,610
from that as an object.

87
00:04:52,610 --> 00:04:54,400
当我们看到系统改变时 
And when we watch the system
change, we think about a

88
00:04:54,400 --> 00:04:57,500
我们想着 信号从这里过来 并且可能在这里改变了一个状态
signal coming in here and
changing a state that might be

89
00:04:57,500 --> 00:04:59,860
并且到了这里 与一个可能储存在这里的状态相互作用
here and going here and
interacting with a state that

90
00:04:59,860 --> 00:05:02,170
等等等等
might be stored there,
and so on and so on.

91
00:05:02,170 --> 00:05:06,860

92
00:05:06,860 --> 00:05:12,760
所以我们想要做的是 我们想要建立一个分散为许多元件的计算机系统来映射我们对现实的观念
So what we'd like is we'd like
to build in the computer

93
00:05:12,760 --> 00:05:17,340

systems that fall into pieces
that mirror our view of

94
00:05:17,340 --> 00:05:19,870
我们构造的真实系统看起来变为许多元件
reality, of the way that the
actual systems we're modeling

95
00:05:19,870 --> 00:05:23,365
seem to fall into pieces.

96
00:05:23,365 --> 00:05:28,970
好吧  可能像这样构建系统的原因
Well, maybe the reason that
building systems like this

97
00:05:28,970 --> 00:05:31,600
看起来介绍如此复杂的科技对计算机没有用
seems to introduce such
technical complications has

98
00:05:31,600 --> 00:05:33,610
nothing to do with computers.

99
00:05:33,610 --> 00:05:37,960
看，或许我们付出了这样的代价去写我们对现实的反映程序
See, maybe the real reason that
we pay such a price to

100
00:05:37,960 --> 00:05:41,910
是我们有对现实错误的理解
write programs that mirror our
view of reality is that we

101
00:05:41,910 --> 00:05:44,550
have the wrong view
of reality.

102
00:05:44,550 --> 00:05:47,460
看 或许时间仅仅是错觉
See, maybe time is just
an illusion, and

103
00:05:47,460 --> 00:05:50,150
什么东西都没有改变
nothing ever changes.

104
00:05:50,150 --> 00:05:52,910
看 打个比方 如果我拿起这支粉笔，然后说
See, for example, if I take this
chalk, and we say, gee,

105
00:05:52,910 --> 00:05:55,820
挖  这是一个对象 并且它有状态
this is an object and
it has a state.

106
00:05:55,820 --> 00:05:59,710
在每个时刻 它有位置和速度
At each moment it has a position
and a velocity.

107
00:05:59,710 --> 00:06:01,240
如果我们对它做了一些事情 它的状态就会改变
And if we do something,
that state can change.

108
00:06:01,240 --> 00:06:04,340

109
00:06:04,340 --> 00:06:07,900
但是如果你学习过相对论 比如
But if you studied any
relativity, for instance, you

110
00:06:07,900 --> 00:06:09,760
你知道 你不会认为粉笔的路径如同某些东西
know that you don't think of
the path of that chalk as

111
00:06:09,760 --> 00:06:11,340
随着时间运动
something that goes on
instant by instant.

112
00:06:11,340 --> 00:06:13,870
把整个粉笔的存在性作为时空中的路径是很有见解的
It's more insightful to think
of that whole chalk's

113
00:06:13,870 --> 00:06:16,020
existence as a path
in space-time.

114
00:06:16,020 --> 00:06:18,040
那全部张开了
that's all splayed out.

115
00:06:18,040 --> 00:06:19,840
这里没有单体的位置和速度
There aren't individual
positions and velocities.

116
00:06:19,840 --> 00:06:24,640
这里仅仅是 在时空中它们的不变的存在性
There's just its unchanging
existence in space-time.

117
00:06:24,640 --> 00:06:28,080
相似的，如果我们看这些电子系统
Similarly, if we look at this
electrical system, if we

118
00:06:28,080 --> 00:06:32,450
如果我们想象这些电子系统是一个实现一些类似信号处理系统
imagine this electrical system
is implementing some sort of

119
00:06:32,450 --> 00:06:35,730
把这些东西放在一起的信号处理工程师
signal processing system, the
signal processing engineer who

120
00:06:35,730 --> 00:06:39,010
不这样想
put that thing together doesn't
think of it as, well,

121
00:06:39,010 --> 00:06:41,490
好吧 在每个瞬间 这里有电压过来
at each instance there's
a voltage coming in.

122
00:06:41,490 --> 00:06:43,340
并且转换成了某些东西
And that translates
into something.

123
00:06:43,340 --> 00:06:46,400
这在这里影响了状态，在这里改变了状态
And that affects the state over
here, which changes the

124
00:06:46,400 --> 00:06:46,810
state over here.

125
00:06:46,810 --> 00:06:49,060
把信号处理系统放在一起的人中没有人会这么想
Nobody putting together a
signal processing system

126
00:06:49,060 --> 00:06:50,420
thinks about it like that.

127
00:06:50,420 --> 00:06:56,830
作为代替 你说这里有信号在时间上伸展
Instead, you say there's
this signal that's

128
00:06:56,830 --> 00:06:58,060
splayed out over time.

129
00:06:58,060 --> 00:07:01,100
如果 这表现的像filter 这整个东西
And if this is acting as a
filter, this whole thing

130
00:07:01,100 --> 00:07:09,570
转换了这整个东西为了一些其他的输出
transforms this whole thing for
some sort of other output.

131
00:07:09,570 --> 00:07:11,790
你不会把它想成状态随着时间的变化
You don't think of it as what's
happening instant by

132
00:07:11,790 --> 00:07:14,160
instant as the state
of these things.

133
00:07:14,160 --> 00:07:17,990
以某种方式 你把这个盒子做为一整个东西
And somehow you think of this
box as a whole thing, not as

134
00:07:17,990 --> 00:07:20,980
而不是一个个在某个特定时刻互相传递状态的元件
little pieces sending messages
of state to each other at

135
00:07:20,980 --> 00:07:22,230

particular instants.

136
00:07:22,230 --> 00:07:28,250

137
00:07:28,250 --> 00:07:30,130
现在 我们准备用另一种比思考交流传递信息的物体更加像信号处理工程师看待世界的方式去分解系统
Well, today we're going to
look at another way to

138
00:07:30,130 --> 00:07:34,260

decompose systems that's more
like the signal processing

139
00:07:34,260 --> 00:07:37,050

engineer's view of the world
than it is like thinking about

140
00:07:37,050 --> 00:07:41,130
objects that communicate
sending messages.

141
00:07:41,130 --> 00:07:43,310
那个被叫做流处理
That's called stream
processing.

142
00:07:43,310 --> 00:07:54,570

143
00:07:54,570 --> 00:08:01,790
我们打算开始展示我们如何编写更加均匀的程序
And we're going to start by
showing how we can make our

144
00:08:01,790 --> 00:08:08,550
并且看更多的共性
programs more uniform and see
a lot more commonality if we

145
00:08:08,550 --> 00:08:12,490
如果我们抛出这些程序
throw out of these programs
what you might say is an

146
00:08:12,490 --> 00:08:17,210
你们可能说的是对时间的过度关心
inordinate concern with
worrying about time.

147
00:08:17,210 --> 00:08:19,910
让我们用对比两个过程来开始
Let me start by comparing
two procedures.

148
00:08:19,910 --> 00:08:23,260

149
00:08:23,260 --> 00:08:25,690
第一个做了这些
The first one does this.

150
00:08:25,690 --> 00:08:27,770
我们想象这里有棵树
We imagine that there's
a tree.

151
00:08:27,770 --> 00:08:30,400

152
00:08:30,400 --> 00:08:33,179
假定这是一个整数的树
Say there's a tree
of integers.

153
00:08:33,179 --> 00:08:34,429
这是一个二叉树
It's a binary tree.

154
00:08:34,429 --> 00:08:39,100

155
00:08:39,100 --> 00:08:40,230
所以这长得像这样
So it looks like this.

156
00:08:40,230 --> 00:08:44,990
并且 在每个树的节点上有整数
And there's integers in
each of the nodes.

157
00:08:44,990 --> 00:08:51,000
我们将要计算的事 对于每个在这里的奇数
And what we would like to
compute is for each odd number

158
00:08:51,000 --> 00:08:54,210
我们想要得到它们的平方 然后再得到它们基于平方的和
sitting here, we'd like to find
the square and then sum

159
00:08:54,210 --> 00:08:57,210
up all those squares.

160
00:08:57,210 --> 00:08:59,480
好吧 那应该是很常见的东西
Well, that should be a familiar
kind of thing.

161
00:08:59,480 --> 00:09:02,930
做这个我们有一个递归策略
There's a recursive strategy
for doing it.

162
00:09:02,930 --> 00:09:04,880
我们看每个叶子
We look at each leaf, and
either it's going to

163
00:09:04,880 --> 00:09:06,690
它们要么贡献数字的平方
contribute the square of
the number if it's odd

164
00:09:06,690 --> 00:09:08,680
如果它是奇数或者 如果是偶数那么就是0
or 0 if it's even.

165
00:09:08,680 --> 00:09:13,280
然后做递归，我们可以说在每个树上
And then recursively, we can say
at each tree, the sum of

166
00:09:13,280 --> 00:09:15,330
所有东西的和是从右括号到左括号
all of them is the sum coming
from the right branch and the

167
00:09:15,330 --> 00:09:17,640
然后随着叶的节点向下递归
left branch, and recursively
down through the nodes.

168
00:09:17,640 --> 00:09:20,360
这是一个很常见的方法去思考编程
And that's a familiar way of
thinking about programming.

169
00:09:20,360 --> 00:09:23,960
让我们看一下课件
Let's actually look at
that on the slide.

170
00:09:23,960 --> 00:09:27,960
我们说 在树上求奇数平方的和 好吧
We say to sum the odd squares
in a tree, well, there's a

171
00:09:27,960 -—> 00:09:30,520
这里有一个测试 要么这是叶节点 并且我们将要去检查 看看它是不是整数
test. Either it's a leaf node,
and we're going to check to

172
00:09:30,520 --> 00:09:34,710
然后要么这是奇数 我们把它平方 要么就是0
see if it's an integer, and then
either it's odd, in which

173
00:09:34,710 --> 00:09:37,160
we take the square,
or else it's 0.

174
00:09:37,160 --> 00:09:40,260
然后 所有东西加起来的和是来自左右括号的和
And then the sum of the whole
thing is the sum coming from

175
00:09:40,260 --> 00:09:42,120
the left branch and
the right branch.

176
00:09:42,120 --> 00:09:46,340

177
00:09:46,340 --> 00:09:51,560
好的 让我们用第二个问题来对比
OK, well, let me contrast that
with a second problem.

178
00:09:51,560 --> 00:09:55,810
假设我给你一个整数n 
Suppose I give you an integer
n, and then some function to

179
00:09:55,810 --> 00:09:59,270
然后再给出一些函数来计算第一个每个在1到n中整数
compute of the first of each
integer in 1 through n.

180
00:09:59,270 --> 00:10:01,810
然后 我想要将它们这些满足一些性质的所有函数值收集起来放到列表中
And then I want to collect
together in a list all those

181
00:10:01,810 --> 00:10:05,600
function values that satisfy
some property.

182
00:10:05,600 --> 00:10:06,880
就是这样
That's a general
kind of thing.

183
00:10:06,880 --> 00:10:09,750
让我们说得具体点 让我们想象
Let's say to be specific, let's
imagine that for each

184
00:10:09,750 --> 00:10:11,270
对于每个整数k 我们将要
integer, k, we're
going to compute

185
00:10:11,270 --> 00:10:14,210
计算出第k个斐波那契数
the k Fibonacci number.

186
00:10:14,210 --> 00:10:17,550
然后我们将会看到哪些是奇数
And then we'll see which of
those are odd and assemble

187
00:10:17,550 --> 00:10:19,050
并将其分配进列表
those into a list.

188
00:10:19,050 --> 00:10:20,710
这里有一个可以做上面这件事的过程
So here's a procedure
that does that.

189
00:10:20,710 --> 00:10:23,730

190
00:10:23,730 --> 00:10:26,240
在第一个n之中 找到奇的斐波那契数
Find the odd Fibonacci numbers
among the first n.

191
00:10:26,240 --> 00:10:28,910
这是我们写的标准循环方法
And here is a standard loop the
way we've been writing it.

192
00:10:28,910 --> 00:10:30,800
这是一个递归
This is a recursion.

193
00:10:30,800 --> 00:10:33,740
这是一个在k上的循环 我们可以说 如果k比n大
It's a loop on k, and says if
k is bigger than n, it's the

194
00:10:33,740 --> 00:10:36,990
这将会是一个空列表 否则我们将会求出第k个斐波那契数
empty list. Otherwise we compute
the k-th Fibonacci

195
00:10:36,990 --> 00:10:40,370
把那个叫做f
number, call that f.

196
00:10:40,370 --> 00:10:45,180
如果这是一个奇数 我们可以使用cons将其变成list
If it's odd, we CONS it on
to the list starting

197
00:10:45,180 --> 00:10:47,690
并以下一个作为开始
with the next one.

198
00:10:47,690 --> 00:10:50,390
否则 我们就取下一个数字
And otherwise, we just
take the next one.

199
00:10:50,390 --> 00:10:52,000
这是一个写iterative loop的标准方法
And this is the standard
way we've been

200
00:10:52,000 --> 00:10:53,000
writing iterative loops.

201
00:10:53,000 --> 00:10:57,600
我们用1来开始循环
And we start off calling
that loop with 1.

202
00:10:57,600 --> 00:11:01,600
所以我们现在有两个过程
OK, so there are
two procedures.

203
00:11:01,600 --> 00:11:02,900
这两个过程看起来很不同
Those procedures look
very different.

204
00:11:02,900 --> 00:11:04,390
他们有两个非常不同的结构
They have very different
structures.

205
00:11:04,390 --> 00:11:07,740
但在某些程度上
Yet from a certain point of
view, those procedures are

206
00:11:07,740 --> 00:11:11,330
那些过程做了相同的事
really doing very much
the same thing.

207
00:11:11,330 --> 00:11:14,930
所以 如果我像信号处理工程师那样说话的话
So if I was talking like a
signal processing engineer,

208
00:11:14,930 --> 00:11:25,730
我会说的可能是第一个过程
what I might say is that the
first procedure enumerates the

209
00:11:25,730 --> 00:11:26,980
enumerate了树中的例子
leaves of a tree.

210
00:11:26,980 --> 00:11:31,160

211
00:11:31,160 --> 00:11:33,510
然后 我们可以想象 一个信号从那里出来
And then we can think of a
signal coming out of that,

212
00:11:33,510 --> 00:11:35,330
它是所有的树节点
which is all the leaves.

213
00:11:35,330 --> 00:11:43,970
我们将会对其进行filter 看看哪些是奇数
We'll filter them to see which
ones are odd, put them through

214
00:11:43,970 --> 00:11:45,190
把这些放进类似的filter
some kind of filter.

215
00:11:45,190 --> 00:11:49,000
我们将会把它们放入transducer
We'll then put them through
a kind of transducer.

216
00:11:49,000 --> 00:11:51,420
对于每个这样的东西 我们将会对其做平方运算
And for each one of those
things, we'll take the square.

217
00:11:51,420 --> 00:11:54,200

218
00:11:54,200 --> 00:11:58,290
然后我们会对所有的这些东西做累加操作
And then we'll accumulate
all of those.

219
00:11:58,290 --> 00:12:00,570
我们将要把这些东西粘住通过从0开始的加法来累加它们
We'll accumulate them by
sticking them together with

220
00:12:00,570 --> 00:12:03,340
addition starting from 0.

221
00:12:03,340 --> 00:12:07,140

222
00:12:07,140 --> 00:12:08,210
这是第一个程序
That's the first program.

223
00:12:08,210 --> 00:12:10,620
第二个程序 我可以用极其相似的方法来形容
The second program, I can
describe in a very, very

224
00:12:10,620 --> 00:12:11,780
similar way.

225
00:12:11,780 --> 00:12:17,450
我会说 我们将在这段1-n的区间中enumerate数字
I'll say, we'll enumerate the
numbers on this interval, for

226
00:12:17,450 --> 00:12:19,080

the interval 1 through n.

227
00:12:19,080 --> 00:12:22,500

228
00:12:22,500 --> 00:12:28,080
对于每一个 我们将要计算出斐波那契数
We'll, for each one, compute the
Fibonacci number, put them

229
00:12:28,080 --> 00:12:29,270
并把它们放进transducer中
through a transducer.

230
00:12:29,270 --> 00:12:31,780
我们将会得到相应的结果
We'll then take the result
of that, and we'll

231
00:12:31,780 --> 00:12:35,976
并且我们将会为了奇数性而filter它
filter it for oddness.

232
00:12:35,976 --> 00:12:39,35
然后我门把它们放进accumulator
And then we'll take those and
put them into an accumulator.

233
00:12:39,350 --> 00:12:41,730
这回 我们将会做一个列表
This time we'll build up a list,
so we'll accumulate with

234
00:12:41,730 --> 00:12:47,110
所以 我们将会用cons从空列表中进行累加
CONS starting from
the empty list.

235
00:12:47,110 --> 00:12:50,940
所以 从这个角度看程序 使这两个程序
So this way of looking at the
program makes the two seem

236
00:12:50,940 --> 00:12:51,900
看起来非常相似
very, very similar.

237
00:12:51,900 --> 00:12:55,880
The problem is that that
commonality is completely

238
00:12:55,880 --> 00:12:58,050
当我们看我们写的程序 这个问题的共同性是完全的被遮蔽的
obscured when we look at the
procedures we wrote.

239
00:12:58,050 --> 00:13:02,670
让我们返回 并再次查看一些奇数的平方
Let's go back and look at some
odd squares again, and say

240
00:13:02,670 --> 00:13:06,300
然后说 enumerator在哪里
things like, where's
the enumerator?

241
00:13:06,300 --> 00:13:08,140
在这个程序里 enumerator在哪里
Where's the enumerator
in this program?

242
00:13:08,140 --> 00:13:11,230
它不在一个地方
Well, it's not in one place.

243
00:13:11,230 --> 00:13:15,990
其中的一部分在这个左节点的测试中
It's a little bit in this
leaf-node test,

244
00:13:15,990 --> 00:13:17,160
这将要停止
which is going to stop.

245
00:13:17,160 --> 00:13:19,380
其中的一小部分在这个东西本身的递归结构中
It's a little bit in the
recursive structure of the

246
00:13:19,380 --> 00:13:20,630
thing itself.

247
00:13:20,630 --> 00:13:23,150

248
00:13:23,150 --> 00:13:24,120
accumulator在哪里
Where's the accumulator?

249
00:13:24,120 --> 00:13:25,680
accumulator也不在一个地方
The accumulator isn't
in one place either.

250
00:13:25,680 --> 00:13:32,180
这东西的一部分在0这 一部分在加号
It's partly in this 0 and
partly in this plus.

251
00:13:32,180 --> 00:13:34,510
不在我们看到的那个东西那里
It's not there as a thing
that we can look at.

252
00:13:34,510 --> 00:13:40,550
相似的 如果我们查看奇数斐波那契数
Similarly, if we look at odd
Fibs, that's also, in some

253
00:13:40,550 --> 00:13:42,940
这在某些程度上 也是一个enumerator和一个accumulator
sense, an enumerator and
an accumulator, but

254
00:13:42,940 --> 00:13:44,470
但这看起来不一样
it looks very different.

255
00:13:44,470 --> 00:13:49,260
因为部分地 enumerator在这测试中大于的符号
Because partly, the enumerator
is here in this greater than

256
00:13:49,260 --> 00:13:52,100
部分地 在整个循环的递归结构
sign in the test. And partly
it's in this whole recursive

257
00:13:52,100 --> 00:13:55,680
structure in the loop, and
the way that we call it.

258
00:13:55,680 --> 00:13:58,100
相似得  accumulator也像这样混合在一起
And then similarly, that's also
mixed up in there with

259
00:13:58,100 --> 00:14:01,010
部分的在这里 部分的在这里
the accumulator, which is partly
over there and partly

260
00:14:01,010 --> 00:14:03,600
over there.

261
00:14:03,600 --> 00:14:09,790
所以 这些非常非常自然的元件
So these very, very natural
pieces, these very natural

262
00:14:09,790 --> 00:14:13,770
这个很自然的盒子不会在我们的程序中出现
boxes here don't appear in our
programs. Because they're kind

263
00:14:13,770 --> 00:14:14,360
因为这些东西混合在一起了
of mixed up.

264
00:14:14,360 --> 00:14:16,290
程序没有正确地将东西切成小块
The programs don't chop things
up in the right way.

265
00:14:16,290 --> 00:14:19,450

266
00:14:19,450 --> 00:14:22,240
让我们回想一下计算机科学的基本定理
Going back to this fundamental
principle of computer science

267
00:14:22,240 --> 00:14:24,620
为了去控制某样东西 你需要
that in order to control
something, you need the name

268
00:14:24,620 --> 00:14:27,820
给它命名  我们真的在用这种方法来思考时没有控制
of it, we don't really have
control over thinking about

269
00:14:27,820 --> 00:14:30,500
因为显式上，我们在那里面没有我们的手
things this way because we don't
have our hands in them

270
00:14:30,500 --> 00:14:31,060
explicitly.

271
00:14:31,060 --> 00:14:35,510
我们没有好的语言来说它们
We don't have a good language
for talking about them.

272
00:14:35,510 --> 00:14:42,850
好吧 让我们发明一个合适的 可以建造这些元件的语言
Well, let's invent an
appropriate language in which

273
00:14:42,850 --> 00:14:44,515
we can build these pieces.

274
00:14:44,515 --> 00:14:48,650
语言的关键是这些东西
The key to the language is these
guys, is what is these

275
00:14:48,650 --> 00:14:50,480
这是一个被我叫做信号的东西
things I called signals?

276
00:14:50,480 --> 00:14:52,070
在盒子中的数组上面飞的东西是什么鬼
What are these things that
are flying on the

277
00:14:52,070 --> 00:14:53,320
arrows between the boxes?

278
00:14:53,320 --> 00:14:56,880

279
00:14:56,880 --> 00:15:02,840
这些东西将变成一种叫流的数据结构
Well, those things are going to
be data structures called

280
00:15:02,840 --> 00:15:04,770
那将变成发明这个语言的关键
streams. That's going
to be the key to

281
00:15:04,770 --> 00:15:07,980
inventing this language.

282
00:15:07,980 --> 00:15:08,600
什么是流
What's a stream?

283
00:15:08,600 --> 00:15:10,820
好吧 一个流是 像其他东西一样
Well, a stream is, like
anything else, a data

284
00:15:10,820 --> 00:15:12,220
一个数据抽象
abstraction.

285
00:15:12,220 --> 00:15:15,000
所以我们应该告诉你什么是selectors
So I should tell you what
its selectors and

286
00:15:15,000 --> 00:15:16,870
什么是constructors
constructors are.

287
00:15:16,870 --> 00:15:20,185
对于一个流 我们将会有一个constructor
For a stream, we're going to
have one constructor that's

288
00:15:20,185 --> 00:15:21,435
叫做 cons流
called CONS-stream.

289
00:15:21,435 --> 00:15:25,690

290
00:15:25,690 --> 00:15:29,060
cons流将会将两个东西合在一起变为一个叫流的东西
CONS-stream is going to put two
things together to form a

291
00:15:29,060 --> 00:15:32,040
thing called a stream.

292
00:15:32,040 --> 00:15:34,250
然后 从流中抽离东西
And then to extract things from
the stream, we're going

293
00:15:34,250 --> 00:15:38,010
我们将会有一个selector 被叫做流的头
to have a selector called
the head of the stream.

294
00:15:38,010 --> 00:15:41,340
所以如果我有一个流 我可以带这个头
So if I have a stream, I
can take its head or I

295
00:15:41,340 --> 00:15:44,720
或者带这个尾
can take its tail.

296
00:15:44,720 --> 00:15:48,290
请记住 我不得不在这里告诉你乔治的合同来告诉你
And remember, I have to tell you
George's contract here to

297
00:15:48,290 --> 00:15:53,160
什么是与这个相关的公理
tell you what the axioms
are that relate these.

298
00:15:53,160 --> 00:16:04,080
对于所有的x和y
And it's going to be for any
x and y, if I form the

299
00:16:04,080 --> 00:16:11,420
如果我造了一个con流并取其头  x和y的cons流的头
CONS-stream and take the head,
the head of CONS-stream of x

300
00:16:11,420 --> 00:16:26,590
将会变成x 并且x和y的cons流的尾将会变成y
and y is going to be x and the
tail of CONS-stream of x and y

301
00:16:26,590 --> 00:16:28,440
is going to be y.

302
00:16:28,440 --> 00:16:31,180
所以那些是对于流的constructor  对于流的2个selectors
So those are the constructor,
two selectors for

303
00:16:31,180 --> 00:16:34,750
和一条公理
streams, and an axiom.

304
00:16:34,750 --> 00:16:36,980
这里有一些可疑
There's something fishy here.

305
00:16:36,980 --> 00:16:41,060
你有可能发现这些完全是cons car cdr的公理
So you might notice that these
are exactly the axioms for

306
00:16:41,060 --> 00:16:46,100
如果写cons流
CONS, CAR, and CDR. If instead
of writing CONS-stream I wrote

307
00:16:46,100 --> 00:16:50,810
并且我说头是car 尾是cdr
CONS and I said head was the
CAR and tail was the CDR,

308
00:16:50,810 --> 00:16:52,810
这些完全是序对的公理
those are exactly the
axioms for pairs.

309
00:16:52,810 --> 00:16:55,130
事实上 这里还有另一个东西
And in fact, there's
another thing here.

310
00:16:55,130 --> 00:17:02,930
我们将会有一个像空列表的东西 叫空流
We're going to have a thing
called the-empty-stream, which

311
00:17:02,930 --> 00:17:08,319
像空列表
is like the-empty-list.

312
00:17:08,319 --> 00:17:10,030
为什么我介绍这个术语呢
So why am I introducing
this terminology?

313
00:17:10,030 --> 00:17:12,780
为什么我不继续说序对和列表呢？
Why don't I just keep talking
about pairs and lists?

314
00:17:12,780 --> 00:17:15,510
好吧 我们将会看到
Well, we'll see.

315
00:17:15,510 --> 00:17:18,440
就现在来说 如果你喜欢 为什么不把流假装
For now, if you like, why don't
you just pretend that

316
00:17:18,440 --> 00:17:21,560
看成列表的一种术语
streams really are just a
terminology for lists.

317
00:17:21,560 --> 00:17:24,890
而且我们等等将会看到 为什么我们想要保持这个额外的抽象层
And we'll see in a little while
why we want to keep this

318
00:17:24,890 --> 00:17:28,150
而不仅仅是叫这个为列表
extra abstraction layer and
not just call them lists.

319
00:17:28,150 --> 00:17:32,300

320
00:17:32,300 --> 00:17:34,860
好的 现在我们有了流 我们可以开始构建
OK, now that we have streams, we
can start constructing the

321
00:17:34,860 --> 00:17:38,990
语言的元件来作用在流上
pieces of the language to
operate on streams. And there

322
00:17:38,990 --> 00:17:41,330
有很多有用的东西我们可以开始做
are a whole bunch of very useful
things that we could

323
00:17:41,330 --> 00:17:42,120
start making.

324
00:17:42,120 --> 00:17:54,850
举个例子 我们将会做我们的map box 来带一个流s
For instance, we'll make our map
box to take a stream, s,

325
00:17:54,850 --> 00:18:00,400
和一个过程 并且生成一个新的流
and a procedure, and to generate
a new stream which

326
00:18:00,400 --> 00:18:03,640
那过程作用在s所有的后继节点上
has as its elements the
procedure applied to all the

327
00:18:03,640 --> 00:18:05,666
作用在s所有的后继节点上
successive elements of s.

328
00:18:05,666 --> 00:18:07,400
事实上 我们已经见过了
In fact, we've seen
this before.

329
00:18:07,400 --> 00:18:10,950
这是我们的过程 这个过程map
了我们在列表中做的
This is the procedure map
that we did with lists.

330
00:18:10,950 --> 00:18:14,000
你看 这完全是map 除了我们要对空流进行测试
And you see it's exactly map,
except we're testing for

331
00:18:14,000 --> 00:18:14,650
empty-stream.

332
00:18:14,650 --> 00:18:15,560
噢 我忘记说了
Oh, I forgot to mention that.

333
00:18:15,560 --> 00:18:19,420
空流就像null测试 所以如果它是空的
Empty-stream is like the null
test. So if it's empty, we

334
00:18:19,420 --> 00:18:20,510
我们生成新的空流
generate the empty stream.

335
00:18:20,510 --> 00:18:24,700
否则 我们做一个新的流 这个流的第一个元素
Otherwise, we form a new stream
whose first element is

336
00:18:24,700 --> 00:18:28,950
是过程作用在流的头
the procedure applied to the
head of the stream, and whose

337
00:18:28,950 --> 00:18:31,570
剩下的将会沿着过程一直map到流的尾部
rest is gotten by mapping along
with the procedure down

338
00:18:31,570 --> 00:18:33,140
the tail of the stream.

339
00:18:33,140 --> 00:18:34,920
所以这和我们以前看过的map过程完全一样
So that looks exactly like
the map procedure

340
00:18:34,920 --> 00:18:37,030
we looked at before.

341
00:18:37,030 --> 00:18:38,350
这里还有另一个有用的东西
Here's another useful thing.

342
00:18:38,350 --> 00:18:40,460
filter 这是我们的filter box
Filter, this is our
filter box.

343
00:18:40,460 --> 00:18:43,890
我们将会有一个谓词和一个流
We're going to have a predicate
and a stream.

344
00:18:43,890 --> 00:18:46,720
我们将会做一个新的包涵所有的满足于谓语元素的流
We're going to make a new stream
that consists of all

345
00:18:46,720 --> 00:18:48,310
the elements of the
original one

346
00:18:48,310 --> 00:18:50,160
that satisfy the predicate.

347
00:18:50,160 --> 00:18:51,270
这里是案例分析
That's case analysis.

348
00:18:51,270 --> 00:18:53,140
当在流中什么都没有
When there's nothing
in the stream, we

349
00:18:53,140 --> 00:18:56,280
我返回一个空的流
return the empty stream.

350
00:18:56,280 --> 00:19:00,060
我们检测在流的头上的谓词
We test the predicate on
the head of the stream.

351
00:19:00,060 --> 00:19:03,520
并且如果这是对的 我们将流的头加在
And if it's true, we add the
head of the stream onto the

352
00:19:03,520 --> 00:19:08,220
filter流尾的结果
result of filtering the
tail of the stream.

353
00:19:08,220 --> 00:19:10,870
否则 如果那个谓词是错的
And otherwise, if that predicate
was false, we just

354
00:19:10,870 --> 00:19:13,500
我们只需要filter流的尾部
filter the tail of the stream.

355
00:19:13,500 --> 00:19:16,595
是的 这里是filter
Right, so there's filter.

356
00:19:16,595 --> 00:19:18,560
让我快速的运行完这一对
Let me run through a couple
more rather quickly.

357
00:19:18,560 --> 00:19:20,880
这些在书里都有 你可以去看下
They're all in the book and
you can look at them.

358
00:19:20,880 --> 00:19:22,110
让我们过一遍
Let me just flash through.

359
00:19:22,110 --> 00:19:23,260
这里是accumulate
Here's accumulate.

360
00:19:23,260 --> 00:19:27,690
accumulate使用一种连接的方式
Accumulate takes a way of
combining things and an

361
00:19:27,690 --> 00:19:31,560
将流中的初始值粘合在一起
initial value in a stream and
sticks them all together.

362
00:19:31,560 --> 00:19:33,970
如果流是空的 那么这仅仅是初始值
If the stream's empty, it's
just the initial value.

363
00:19:33,970 --> 00:19:36,930
否则 我们连接流的头和累加从初始值开始的流的尾部的结果
Otherwise, we combine the head
of the stream with the result

364
00:19:36,930 --> 00:19:39,550
of accumulating the tail of the
stream starting from the

365
00:19:39,550 --> 00:19:40,900
initial value.

366
00:19:40,900 --> 00:19:42,830
所以 我们将会将所有东西都加进流
So that's what I'd use to add
up everything in the stream.

367
00:19:42,830 --> 00:19:45,830
我会使用加法来进行累加
I'd accumulate with plus.

368
00:19:45,830 --> 00:19:48,060
我如何enumerate树上的叶子呢
How would I enumerate the
leaves of a tree?

369
00:19:48,060 --> 00:19:54,530
如果树仅仅只是叶本身
Well, if the tree is just a leaf
itself, I make something

370
00:19:54,530 --> 00:19:56,640
我制作一个只有节点的东西
which only has that
node in it.

371
00:19:56,640 --> 00:20:01,100
否则 我把从左括号到右括号的东西附加起来
Otherwise, I append together the
stuff of enumerating the

372
00:20:01,100 --> 00:20:04,340
left branch and the
right branch.

373
00:20:04,340 --> 00:20:08,130
然后 在这里附加就像普通在列表中的附加
And then append here is like the
ordinary append on lists.

374
00:20:08,130 --> 00:20:13,190

375
00:20:13,190 --> 00:20:13,850
你可以看这里
You can look at that.

376
00:20:13,850 --> 00:20:16,410
这类似于普通附加两个列表的过程
That's analogous to the
ordinary procedure for

377
00:20:16,410 --> 00:20:19,150
appending two lists.

378
00:20:19,150 --> 00:20:21,810
我如何来enumerate间距
How would I enumerate
an interval?

379
00:20:21,810 --> 00:20:24,500
这将会用到两个数 一小一大
This will take two integers, low
and high, and generate a

380
00:20:24,500 --> 00:20:28,106
并且生成从小到大的整数流
stream of the integers going
from low to high.

381
00:20:28,106 --> 00:20:31,890
然后我们可得到整个一串元件
And we can make a whole
bunch of pieces.

382
00:20:31,890 --> 00:20:34,860
所以 那是我们说的流的一点点小语言
So that's a little language of
talking about streams. Once we

383
00:20:34,860 --> 00:20:37,670
当我们有了流 我们可以制作东西来操纵它们
have streams, we can build
things for manipulating them.

384
00:20:37,670 --> 00:20:40,200
再说一下 我们正在制作语言
Again, we're making
a language.

385
00:20:40,200 --> 00:20:41,270
现在我们可以用这种语言来表达东西
And now we can start expressing

386
00:20:41,270 --> 00:20:43,060
things in this language.

387
00:20:43,060 --> 00:20:46,590
这里是在树中累加奇数平方的原始过程
Here's our original procedure
for summing the odd

388
00:20:46,590 --> 00:20:47,310
squares in a tree.

389
00:20:47,310 --> 00:20:52,210
你将会注意到 这完全像方框图
And you'll notice it looks
exactly now like the block

390
00:20:52,210 --> 00:20:54,590
像信号处理中的方框图
diagram, like the signal
processing block diagram.

391
00:20:54,590 --> 00:21:00,230
所以把奇数的平方在树中求和
So to sum the odd squares in a
tree, we enumerate the leaves

392
00:21:00,230 --> 00:21:01,320
我们enumerate了数中的叶子
of the tree.

393
00:21:01,320 --> 00:21:04,830
我们为了保持奇数性进行filter
We filter that for oddness.

394
00:21:04,830 --> 00:21:06,220
我们为了平方性进行map
We map that for squareness.

395
00:21:06,220 --> 00:21:09,320

396
00:21:09,320 --> 00:21:12,460
并且我们使用加法对结果进行累加
And we accumulate the result
of that using addition,

397
00:21:12,460 --> 00:21:14,760
从0开始
starting from 0.

398
00:21:14,760 --> 00:21:17,290
所以我们可以看到我们想要的元件
So we can see the pieces
that we wanted.

399
00:21:17,290 --> 00:21:22,050
相似的 斐波那契数 我们怎样得到奇数的斐波那契数
Similarly, the Fibonacci one,
how do we get the odd Fibs?

400
00:21:22,050 --> 00:21:27,900
我们从1到n枚举间距 并沿着那里进行map
Well, we enumerate the interval
from 1 to n, we map

401
00:21:27,900 --> 00:21:30,920
计算每个的斐波那契数
along that, computing the
Fibonacci of each one.

402
00:21:30,920 --> 00:21:34,810
我们为了奇数性对那些结果进行filter
We filter the result of
those for oddness.

403
00:21:34,810 --> 00:21:38,460
并且我们使用从空列表开始的cons累积了所有的这些东西
And we accumulate all of that
stuff using CONS starting from

404
00:21:38,460 --> 00:21:43,650
the empty-list.

405
00:21:43,650 --> 00:21:47,680
好吧 那这个有神马优势
OK, what's the advantage
of this?

406
00:21:47,680 --> 00:21:50,260
嗯 首先 我们现在有元件 并且我们可以开始
Well, for one thing, we now have
pieces that we can start

407
00:21:50,260 --> 00:21:51,880
混合和匹配
mixing and matching.

408
00:21:51,880 --> 00:21:58,230
举个例子 如果我想要改变它
So for instance, if I wanted to
change this, if I wanted to

409
00:21:58,230 --> 00:22:00,400
如果我想要得到整数的平方 然后进行filter
compute the squares of the
integers and then filter them,

410
00:22:00,400 --> 00:22:03,810
我需要做的是从那个平方中拿起像这样的标准元件 然后放进去
all I need to do is pick up a
standard piece like this in

411
00:22:03,810 --> 00:22:06,210
that square and put it in.

412
00:22:06,210 --> 00:22:10,150
或者 如果我们想要计算整个在树上的斐波那契计算而不是一个序列
Or if we wanted to do this whole
Fibonacci computation on

413
00:22:10,150 --> 00:22:12,980

the leaves of a tree rather than
a sequence, all I need to

414
00:22:12,980 --> 00:22:18,030
我需要做的是用那个替换这个enumerator
do is replace this enumerator
with that one.

415
00:22:18,030 --> 00:22:20,650
看 流处理的优势是
See, the advantage of this
stream processing is that

416
00:22:20,650 --> 00:22:21,995
我们建立了－－
we're establishing--

417
00:22:21,995 --> 00:22:25,330
这是我们课程中一个比较大的课题
this is one of the big themes
of the course--

418
00:22:25,330 --> 00:22:35,570
我们正在建立符合我们直觉的接口 并且这个接口允许我们把东西粘在一起
we're establishing conventional
interfaces that

419
00:22:35,570 --> 00:22:38,130
allow us to glue things
together.

420
00:22:38,130 --> 00:22:41,730
像map和filter这样的东西是一个标准的组件集合
Things like map and filter are
a standard set of components

421
00:22:41,730 --> 00:22:43,900
我们可以开始使用这个 并用各种各样的方法去粘合程序
that we can start using for
pasting together programs in

422
00:22:43,900 --> 00:22:45,750
all sorts of ways.

423
00:22:45,750 --> 00:22:50,090
这让我们看到程序的共性
It allows us to see the
commonality of programs.

424
00:22:50,090 --> 00:22:52,390
我应该说一下 我只展示给你们2个过程
I just ought to mention, I've
only showed you two

425
00:22:52,390 --> 00:22:53,860
procedures.

426
00:22:53,860 --> 00:22:57,800
但是 让我强调一下
But let me emphasize that this
way of putting things together

427
00:22:57,800 --> 00:22:59,780
这种用maps filters和accumulators 把东西放在一起的方法
with maps, filters,
and accumulators

428
00:22:59,780 --> 00:23:01,410
是非常非常普通的
is very, very general.

429
00:23:01,410 --> 00:23:08,010
这是程序产生和测试的范式
It's the generate and test
paradigm for programs. And as

430
00:23:08,010 --> 00:23:11,970
作为一个列子 曾经的麻省理工研究生 Richard Waters
an example of that, Richard
Waters, who was at MIT when he

431
00:23:11,970 --> 00:23:14,060

was a graduate student, as part
of his thesis research

432
00:23:14,060 --> 00:23:17,700
他把分析一个大块的ibm科学图书管子程序作为它理论研究的一部分
went and analyzed a large chunk
of the IBM scientific

433
00:23:17,700 --> 00:23:22,340
他发现 大约百分之60的程序
subroutine library, and
discovered that about 60% of

434
00:23:22,340 --> 00:23:26,830
可以用不超过我们放在这里的知识完整的表达
the programs in it could be
expressed exactly in terms

435
00:23:26,830 --> 00:23:28,940
using no more than what
we've put here--

436
00:23:28,940 --> 00:23:30,710
map filter accumulate
map, filter, and accumulate.

437
00:23:30,710 --> 00:23:31,960
好的 下面进入休息时间
All right, let's take a break.

438
00:23:31,960 --> 00:23:36,620

439
00:23:36,620 --> 00:23:37,870
有神马问题
Questions?

440
00:23:37,870 --> 00:23:40,470

441
00:23:40,470 --> 00:23:43,030
学僧 ：看起来这货的本质只是
AUDIENCE: It seems like the
essence of this whole thing is

442
00:23:43,033 --> 00:23:45,980
你有一个非常均匀简单的数据结构来进行工作 这个数据结构叫流
just that you have a very
uniform, simple data structure

443
00:23:45,980 --> 00:23:48,380
to work with, the stream.

444
00:23:48,380 --> 00:23:48,920
教授：是的
PROFESSOR: Right.

445
00:23:48,920 --> 00:23:51,670
本质就是这个
The essence is that you, again,
it's this sense of

446
00:23:51,670 --> 00:23:53,710
再说一下 这个就是感觉符合直觉的接口
conventional interfaces.

447
00:23:53,710 --> 00:23:55,610
所以你可以开始把很多东西放在一起
So you can start putting a
lot of things together.

448
00:23:55,610 --> 00:23:59,830
流就像你所说的那样 一种均衡的数据结构来支持它
And the stream is as you say,
the uniform data structure

449
00:23:59,830 --> 00:24:00,890
that supports that.

450
00:24:00,890 --> 00:24:03,600
顺便说一下 这非常像APL
This is very much like
APL, by the way.

451
00:24:03,600 --> 00:24:06,330
APL是一个几乎相同的思想 除了在APL中
APL is very much the same idea,
except in APL, instead

452
00:24:06,330 --> 00:24:09,560
你可以使用数组和向量来代替这个流
of this stream, you have
arrays and vectors.

453
00:24:09,560 --> 00:24:13,565
并且APL许多的威力的原因完全和这个一样
And a lot of the power of APL is
exactly the same reason of

454
00:24:13,565 --> 00:24:14,815
the power of this.

455
00:24:14,815 --> 00:24:19,910

456
00:24:19,910 --> 00:24:20,910
好的 谢谢
OK, thank you.

457
00:24:20,910 --> 00:24:22,160
休息一下
Let's take a break.

458
00:24:22,160 --> 00:24:57,470

459
00:24:57,470 --> 00:24:57,610
好的
All right.

460
00:24:57,610 --> 00:25:02,830
我们已经看到使用流来做组织计算
We've been looking at ways of
organizing computations using

461
00:25:02,830 --> 00:25:07,560
我现在想要做的只是展示给你们
streams. What I want to do now
is just show you two somewhat

462
00:25:07,560 --> 00:25:10,810
两个更加复杂的例子
more complicated examples
of that.

463
00:25:10,810 --> 00:25:15,000
让我们开始思考下面重要有用的过程
Let's start by thinking about
the following kind of utility

464
00:25:15,000 --> 00:25:16,810
procedure that will
come in useful.

465
00:25:16,810 --> 00:25:19,960
假设我有一个流
Suppose I've got a stream.

466
00:25:19,960 --> 00:25:23,730
流中的元素本身就是一个流
And the elements of this stream
are themselves streams.

467
00:25:23,730 --> 00:25:26,530
所以一开始可能是1，2，3
So the first thing
might be 1, 2, 3.

468
00:25:26,530 --> 00:25:32,600

469
00:25:32,600 --> 00:25:33,880
我得到了一个流
So I've got a stream.

470
00:25:33,880 --> 00:25:40,100
并且每个流中的元素它本身就是一个流
And each element of the stream
is itself a stream.

471
00:25:40,100 --> 00:25:45,580
我想要做的是 建造一个流
And what I'd like to do is build
a stream that collects

472
00:25:45,580 --> 00:25:47,870
它收集了所有的元素 将所有的元素脱离这个子流
together all of the elements,
pulls all of the elements out

473
00:25:47,870 --> 00:25:50,840
然后把它们进行字符串化变成一个东西
of these sub-streams and
strings them all

474
00:25:50,840 --> 00:25:52,080
together in one thing.

475
00:25:52,080 --> 00:25:56,220
只是展示给你这个语言的作用 真简单
So just to show you the use of
this language, how easy it is,

476
00:25:56,220 --> 00:25:56,960
把那个叫做flatten
call that flatten.

477
00:25:56,960 --> 00:26:13,020
然后我可以定义过程来flatten这个流中流
And I can define to flatten this
stream of streams. Well,

478
00:26:13,020 --> 00:26:13,960
这是什么鬼
what is that?

479
00:26:13,960 --> 00:26:16,240
那只是一个accumulation
That's just an accumulation.

480
00:26:16,240 --> 00:26:25,240
我想使用附加做累加
I want to accumulate
using append, by

481
00:26:25,240 --> 00:26:26,450
通过连续的附加
successively appending.

482
00:26:26,450 --> 00:26:36,590
所以 我使用了 附加流进行累加
So I accumulate using append
streams, starting with

483
00:26:36,590 --> 00:26:54,370
从空流往下到 流中流
the-empty-stream down that
stream of streams.

484
00:26:54,370 --> 00:26:58,290
这里有一个你怎样开始使用这些更高阶的东西去做一些有趣的操作的例子
OK, so there's an example of how
you can start using these

485
00:26:58,290 --> 00:27:00,830
higher order things to do some
interesting operations.

486
00:27:00,830 --> 00:27:04,230
事实上 我还想做另一个有趣的东西
In fact, there's another
useful thing

487
00:27:04,230 --> 00:27:05,100
that I want to do.

488
00:27:05,100 --> 00:27:18,700
我想要定义一个叫flat-map的过程
I want to define a procedure
called flat-map, flat map of

489
00:27:18,700 --> 00:27:21,840
一些函数和一个流的flat map
some function and a stream.

490
00:27:21,840 --> 00:27:23,920
f将会变成一个有一些元素的流
And what this is going
to do is f will

491
00:27:23,920 --> 00:27:25,720
be a stream of elements.

492
00:27:25,720 --> 00:27:28,930
f将会变成一个函数
f is going to be a function that
for each element in the

493
00:27:28,930 --> 00:27:31,950
这个函数在流中的每个元素可以产生另一个流
stream produces another
stream.

494
00:27:31,950 --> 00:27:33,950
我想要做的是把所有的元素和所有的流合并起来
And what I want to do is take
all of the elements and all of

495
00:27:33,950 --> 00:27:36,000
those streams and combine
them together.

496
00:27:36,000 --> 00:27:51,350
所以那个只将会是直到s的flatten of map f
So that's just going to be the
flatten of map f down s.

497
00:27:51,350 --> 00:27:54,290
每次我调用对元素s调用f 我得到一个流
Each time I apply f to an
element of s, I get a stream.

498
00:27:54,290 --> 00:27:56,690
如果我像下做map 我将会得到一个流中流
If I map it all the way down, I
get a stream of streams, and

499
00:27:56,690 --> 00:27:58,385
并且我将会将它flatten
I'll flatten that.

500
00:27:58,385 --> 00:28:04,670
好 我想要使用这个来展示给你们一种新的方法来熟悉这样的问题
Well, I want to use that to
show you a new way to do a

501
00:28:04,670 --> 00:28:06,360
familiar kind of problem.

502
00:28:06,360 --> 00:28:12,310
这个问题和你以前见过的许多问题一样
The problem's going to be like a
lot of problems you've seen,

503
00:28:12,310 --> 00:28:14,190
虽然这个可能不是很特别
although maybe not this
particular one.

504
00:28:14,190 --> 00:28:15,490
我将会给你一个整数n
I'm going to give you
an integer, n.

505
00:28:15,490 --> 00:28:18,480

506
00:28:18,480 --> 00:28:31,020
我们的问题是找到所有的序对和整数i和j
And the problem is going to be
find all pairs and integers i

507
00:28:31,020 --> 00:28:42,740
取值为0-i j小于i 一直到n
and j, between 0 and i, with j
less than i, up to n, such

508
00:28:42,740 --> 00:28:51,910
并且可以满足i＋j是素数
that i plus j is prime.

509
00:28:51,910 --> 00:28:55,740

510
00:28:55,740 --> 00:29:00,520
举个例子 如果n＝6 让我在这里做个小表格
So for example, if n equals 6,
let's make a little table

511
00:29:00,520 --> 00:29:06,640
这里i,j,i+j
here, i and j and i plus j.

512
00:29:06,640 --> 00:29:09,700

513
00:29:09,700 --> 00:29:15,520
我们可以假设 i=2 j=1 我门可以得到i+j=3
So for, say, i equals 2 and
j equals 1, I'd get 3.

514
00:29:15,520 --> 00:29:18,940
对于i=3 我可以使j＝2
And for i equals 3, I could
have j equals 2, and that

515
00:29:18,940 --> 00:29:21,210
那么i＋j＝5
would be 5.

516
00:29:21,210 --> 00:29:28,400
如果i＝4 j＝1 i＋j＝5 等等 直到i到了6
And 4 and 1 would be 5 and so
on, up until i goes to 6.

517
00:29:28,400 --> 00:29:33,640
我想要返回去产生三倍数像这样的一个流
And what I'd like to return is
to produce a stream of all the

518
00:29:33,640 --> 00:29:37,350
让我们说 i j i+j
triples like this, let's
say i, j, and i plus j.

519
00:29:37,350 --> 00:29:41,530
所以对于每个n 我想要产生这个流
So for each n, I want to
generate this stream.

520
00:29:41,530 --> 00:29:43,680
好的 这简单
OK, well, that's easy.

521
00:29:43,680 --> 00:29:47,230
让我们做吧
Let's build it up.

522
00:29:47,230 --> 00:29:50,150
我们像这样开始
We start like this.

523
00:29:50,150 --> 00:29:55,510
我们会说 对于每个i 我们将会产生一个流
We're going to say for
each i, we're going

524
00:29:55,510 --> 00:29:56,440
to generate a stream.

525
00:29:56,440 --> 00:29:58,830
对于每个1到n的i 我们将会产生一个流
For each i in the interval 1
through n, we're going to

526
00:29:58,830 --> 00:30:00,660
generate a stream.

527
00:30:00,660 --> 00:30:02,230
这个流将会变成什么呢
What's that stream
going to be?

528
00:30:02,230 --> 00:30:04,180
我们将会以产生所有的序对开始
We're going to start by
generating all the pairs.

529
00:30:04,180 --> 00:30:11,840
所以 对于我们产生的每个i 
So for each i, we're going to
generate, for each j in the

530
00:30:11,840 --> 00:30:19,450
都有在这个1到i－1的区间里每个j 我们将会产生序对
interval 1 to i minus 1, we'll
generate the pair, or the list

531
00:30:19,450 --> 00:30:20,710
或者是一个有两个元素i 和j的列表
with two elements i and j.

532
00:30:20,710 --> 00:30:23,780

533
00:30:23,780 --> 00:30:30,712
所以我们map整个区间 生成这些序对
So we map along the interval,
generating the pairs.

534
00:30:30,712 --> 00:30:33,170
对于每个产生一个序对的流的i
And for each i, that generates
a stream of pairs.

535
00:30:33,170 --> 00:30:34,590
然后我们flatmap它
And we flatmap it.

536
00:30:34,590 --> 00:30:37,390
现在 我们已经拥有了所有i和j的序对
Now we have all the pairs
i and j, such that i

537
00:30:37,390 --> 00:30:38,730
并且i比j小
is less than j.

538
00:30:38,730 --> 00:30:39,850
就像这样搞
So that builds that.

539
00:30:39,850 --> 00:30:42,990
现在我们对其来个测试
Now we're got to test them.

540
00:30:42,990 --> 00:30:47,160
我们把我们刚刚建的东西拿出 flatmap
Well, we take that thing we just
built, the flatmap, and

541
00:30:47,160 --> 00:30:50,090
并且我们把它进行filter 这个i是否
we filter it to see
whether the i--

542
00:30:50,090 --> 00:30:51,660
看 我们有一个i和j
see, we had an i and a j.

543
00:30:51,660 --> 00:30:55,180
i是列表中的第一个东西 j是第二个
i was the first thing in the
list, j was the second thing

544
00:30:55,180 --> 00:30:59,030
在列表中 我们有一个谓词
in the list. So we have a
predicate which says in that

545
00:30:59,030 --> 00:31:00,870
这个谓词表示 在这个由2个元素构成的列表是car和cdr素数的和
list of two elements
is the sum of the

546
00:31:00,870 --> 00:31:02,070
CAR and the CDR prime.

547
00:31:02,070 --> 00:31:06,540
并且我们对序对的集合进行filter
And we filter that collection
of pairs we just built.

548
00:31:06,540 --> 00:31:09,420
所以 那些是我们想要的序对
So those are the
pairs we want.

549
00:31:09,420 --> 00:31:13,340
现在 我们继续 把filter后的结构沿着它进行map
Now we go ahead and we take the
result of that filter and

550
00:31:13,340 --> 00:31:19,610
生成列表i和j i+j
we map along it, generating the
list i and j and i plus j.

551
00:31:19,610 --> 00:31:22,910
这就是我们的程序 prime-sum-pairs
And that's our procedure
prime-sum-pairs.

552
00:31:22,910 --> 00:31:24,480
然后只需要过一遍  这就是我们整个过程了
And then just to flash it up,
here's the whole procedure.

553
00:31:24,480 --> 00:31:27,945

554
00:31:27,945 --> 00:31:30,750
一个map 一个filter 一个flatmap
A map, a filter, a flatmap.

555
00:31:30,750 --> 00:31:34,850

556
00:31:34,850 --> 00:31:36,350
所有的东西都在这里了
There's the whole thing,
even though this isn't

557
00:31:36,350 --> 00:31:37,120
即使这个可读性不高
particularly readable.

558
00:31:37,120 --> 00:31:40,000
这只是一个flatmap的延伸
It's just expanding
that flatmap.

559
00:31:40,000 --> 00:31:45,090
这里有一个表现嵌套循环的过程
So there's an example which
illustrates the general point

560
00:31:45,090 --> 00:31:49,350
它开始像maps和那些东西的flatmaps的flatmaps的flatmaps

that nested loops in this
procedure start looking like

561
00:31:49,350 --> 00:31:52,370
compositions of flatmaps of
flatmaps of flatmaps of maps

562
00:31:52,370 --> 00:31:54,200
and things.

563
00:31:54,200 --> 00:31:57,900
所以我们不仅仅要枚举单个个体
So not only can we enumerate
individual things, but by

564
00:31:57,900 --> 00:32:00,890
还要通过使用flatmaps 使我们做一些与大部分其他语言的对应的嵌套循环
using flatmaps, we can do what
would correspond to nested

565
00:32:00,890 --> 00:32:03,230
loops in most other languages.

566
00:32:03,230 --> 00:32:06,870
当然 一直写这个flatmaps中的flatmaps很烦
Of course, it's pretty awful to
keep writing these flatmaps

567
00:32:06,870 --> 00:32:08,410
of flatmaps of flatmaps.

568
00:32:08,410 --> 00:32:13,830
你看的这个prime-sum-pairs很复杂
Prime-sum-pairs you saw looked
fairly complicated, even

569
00:32:13,830 --> 00:32:15,480
虽然单个个体很容易
though the individual
pieces were easy.

570
00:32:15,480 --> 00:32:17,800
所以如果你喜欢 你可以用一些叫collect的语法糖
So what you can do, if you
like, is introduced some

571
00:32:17,800 --> 00:32:21,040
syntactic sugar that's
called collect.

572
00:32:21,040 --> 00:32:23,570
collect只是一个对于嵌套的flatmaps的缩写
And collect is just an
abbreviation for that nest of

573
00:32:23,570 --> 00:32:26,160

flatmaps and filters arranged
in that particular way.

574
00:32:26,160 --> 00:32:29,620
这里还是prime-sum-pairs 不过是用collect来做的
Here's prime-sum-pairs again,
written using collect.

575
00:32:29,620 --> 00:32:32,670
它的意思是为了找到所有的序对 我将要整和一个答案
It says to find all those pairs,
I'm going to collect

576
00:32:32,670 --> 00:32:40,910
这个答案是列表i j 和i+j
together a result, which is the
list i, j, and i plus j,

577
00:32:40,910 --> 00:32:44,510
那将会生成i的值为1到n
that's going to be generated as
i runs through the interval

578
00:32:44,510 --> 00:32:51,440
j的值是1到i到1
from 1 to n and as j runs
through the interval from 1 to

579
00:32:51,440 --> 00:32:58,040
并令i＋j是素数
i minus 1, such that
i plus j is prime.

580
00:32:58,040 --> 00:33:00,690
所以我将不会说 我会使用一般的collect
So I'm not going to say what
collect does in general.

581
00:33:00,690 --> 00:33:03,420
你可以在书上看到它
You can look at that by looking
at it in the book.

582
00:33:03,420 --> 00:33:06,010
但是 很显然 你可以看到这些元件是我写的原始过程的元件
But pretty much, you can see
that the pieces of this are

583
00:33:06,010 --> 00:33:08,820
the pieces of that original
procedure I wrote.

584
00:33:08,820 --> 00:33:11,550
这个collect只是一些自动生成嵌套flatmaps的语法糖
And this collect is just some
syntactic sugar for

585
00:33:11,550 --> 00:33:16,310
automatically generating that
nest of flatmaps and flatmaps.

586
00:33:16,310 --> 00:33:21,120
好 让我再做一个和上面差不多的例子
OK, well, let me do one more
example that shows you the

587
00:33:21,120 --> 00:33:22,120
same kind of thing.

588
00:33:22,120 --> 00:33:25,740
这里是一个非常著名的问题
Here's a very famous problem
that's used to illustrate a

589
00:33:25,740 --> 00:33:28,980
这个问题以前是为了展示许多叫回溯法的计算机算法
lot of so-called backtracking
computer algorithms. This is

590
00:33:28,980 --> 00:33:30,200
这是一个八皇后的问题
the eight queens problem.

591
00:33:30,200 --> 00:33:32,370
这里是棋盘
This is a chess board.

592
00:33:32,370 --> 00:33:34,570
八皇后问题说
And the eight queens problem
says, find a way to put down

593
00:33:34,570 --> 00:33:37,660
找到一种八皇后两两不相攻击的方法
eight queens on a chess board
so that no two are attacking

594
00:33:37,660 --> 00:33:38,000
each other.

595
00:33:38,000 --> 00:33:39,685
这里有一个特别的方法来解决这个八皇后问题
And here's a particular
solution to the

596
00:33:39,685 --> 00:33:41,430
eight queens problem.

597
00:33:41,430 --> 00:33:44,450
所以 我得保证放置皇后 并且
So I have to make sure to put
down queens so that no two are

598
00:33:44,450 --> 00:33:48,570
没有皇后在同一列或行或在同一个对角线
in the same row or the
same column or sit

599
00:33:48,570 --> 00:33:51,410
along the same diagonal.

600
00:33:51,410 --> 00:33:56,400
现在有个做这个的标准的方法
Now, there's sort of a standard
way of doing that.

601
00:33:56,400 --> 00:33:59,740

602
00:33:59,740 --> 00:34:03,200
首先我们要做的是
Well, first we need
to do is below the

603
00:34:03,200 --> 00:34:04,940
站在george的层面
surface, at George's level.

604
00:34:04,940 --> 00:34:07,340
我们得找一个方法来表示棋盘和位置
We have to find some way to
represent a board, and

605
00:34:07,340 --> 00:34:08,095

represent positions.

606
00:34:08,095 --> 00:34:09,800
我们不需要担心那个
And we'll not worry
about that.

607
00:34:09,800 --> 00:34:12,540
但是让我们假设有一个叫safe的谓词
But let's assume that there's
a predicate called safe.

608
00:34:12,540 --> 00:34:16,040

609
00:34:16,040 --> 00:34:19,090
safe所作的是
And what safe is going to do is
going to say given that I

610
00:34:19,090 --> 00:34:22,520
我有一串皇后放在棋盘上
have a bunch of queens down on
the chess board, is it OK to

611
00:34:22,520 --> 00:34:25,400
把queen放在特定的点上是好的吗
put a queen in this
particular spot?

612
00:34:25,400 --> 00:34:32,889
所以safe将会带一行一列
So safe is going to take
a row and a column.

613
00:34:32,889 --> 00:34:34,510
那将会是我尝试放置下一个皇后的地方和剩下的地方
That's going to be a place where
I'm going to try and put

614
00:34:34,510 --> 00:34:42,370
down the next queen, and
the rest of positions.

615
00:34:42,370 --> 00:34:45,420

616
00:34:45,420 --> 00:34:48,679
safe说的是 我已经把皇后放在这个位置上
And what safe will say is given
that I already have

617
00:34:48,679 --> 00:34:53,920
queens down in these positions,
is it safe to put

618
00:34:53,920 --> 00:34:58,300
那么 把皇后放在那个行或列是safe吗
another queen down in that
row and that column?

619
00:34:58,300 --> 00:34:59,360
让我们不要再担心这个问题
And let's not worry
about that.

620
00:34:59,360 --> 00:35:01,380
这个是乔治的问题 这也不难写
That's George's problem. and
it's not hard to write.

621
00:35:01,380 --> 00:35:06,350
你只需要检查 这货是不是包含
You just have to check whether
this thing contains any things

622
00:35:06,350 --> 00:35:10,530
一些在那个行 列或对角线中的东西
on that row or that column
or in that diagonal.

623
00:35:10,530 --> 00:35:13,590
现在你将要怎样组织程序呢
Now, how would you organize
the program given that?

624
00:35:13,590 --> 00:35:18,010
这里有一个传统的方法来解决这个问题
And there's sort of a
traditional way to organize it

625
00:35:18,010 --> 00:35:20,116
我们把它叫做回溯法 它的意思是
called backtracking.

626
00:35:20,116 --> 00:35:27,570
让我们把第一个皇后放在第一个列上
And it says, well, let's think
about all the ways of putting

627
00:35:27,570 --> 00:35:31,290
the first queen down in
the first column.

628
00:35:31,290 --> 00:35:32,580
这里有八种方法
There are eight ways.

629
00:35:32,580 --> 00:35:35,880
让我们来试一下第一个
Well, let's say try
the first column.

630
00:35:35,880 --> 00:35:37,300
来试试第一行第一列
Try column 1, row 1.

631
00:35:37,300 --> 00:35:41,300
这些分支可以表示每个的可能性
These branches are going to
represent the possibilities at

632
00:35:41,300 --> 00:35:43,360
each level.

633
00:35:43,360 --> 00:35:45,875
所以我将会尝试并把皇后放在第一列中
So I'll try and put a queen
down in the first column.

634
00:35:45,875 --> 00:35:48,360
现在 我们已经把它放在第一列了
And now given that it's in the
first column, I'll try and put

635
00:35:48,360 --> 00:35:49,980
我们讲尝试把下一个皇后放在第一列
the next queen down in
the first column.

636
00:35:49,980 --> 00:35:53,035

637
00:35:53,035 --> 00:35:55,470
我们将尝试并且把第一个皇后
I'll try and put the first
queen, the one in the first

638
00:35:55,470 --> 00:35:56,920
第一列的皇后 方在第一行
column, down in the first row.

639
00:35:56,920 --> 00:35:59,050
不好意思
I'm sorry.

640
00:35:59,050 --> 00:36:00,780
然后 我们将把下一个皇后放在第一行
And then given that, we'll
put the next queen down

641
00:36:00,780 --> 00:36:01,390
in the first row.

642
00:36:01,390 --> 00:36:02,090
这样不好
And that's no good.

643
00:36:02,090 --> 00:36:04,200
所以我将要返回到这里
So I'll back up to here.

644
00:36:04,200 --> 00:36:06,280
我会说 我能把第一个皇后放在第二行吗
And I'll say, oh, can I put the
first queen down in the

645
00:36:06,280 --> 00:36:07,510
second row?

646
00:36:07,510 --> 00:36:08,550
好吧 这样也不好
Well, that's no good.

647
00:36:08,550 --> 00:36:09,760
喔 我能把这个放在第三行嘛
Oh, can I put it down
in the third row?

648
00:36:09,760 --> 00:36:12,790
好 这样不错
Well, that's good.

649
00:36:12,790 --> 00:36:14,290
现在 我能把第一个皇后放在第一列吗
Well, now can I put the
next queen down

650
00:36:14,290 --> 00:36:15,380
in the first column?

651
00:36:15,380 --> 00:36:18,030
我不能再想象棋盘
Well, I can't visualize this
chess board anymore, but I

652
00:36:18,030 --> 00:36:19,195
但是我觉得这样是对的
think that's right.

653
00:36:19,195 --> 00:36:20,450
并且 我将尝试下一个
And I try the next one.

654
00:36:20,450 --> 00:36:24,170
在每个地方 我尽可能的沿着数向下
And at each place, I go as far
down this tree as I can.

655
00:36:24,170 --> 00:36:25,640
然后倒退
And I back up.

656
00:36:25,640 --> 00:36:28,970
如果我到了这里 并且发现我不能再往下了
If I get down to here and find
no possibilities below there,

657
00:36:28,970 --> 00:36:31,740
我返回到这里 再次开始生成这个子树
I back all the way up to here,
and now start again generating

658
00:36:31,740 --> 00:36:33,260
this sub-tree.

659
00:36:33,260 --> 00:36:35,050
并且我四处绕
And I sort of walk around.

660
00:36:35,050 --> 00:36:37,870
最后 如果我可以一路求解下来
And finally, if I ever manage to
get all the way down, I've

661
00:36:37,870 --> 00:36:40,090
我将会得到答案
found a solution.

662
00:36:40,090 --> 00:36:45,020
这就是以前在人工智能编程中传统的范式
So that's a typical sort of
paradigm that's used a lot in

663
00:36:45,020 --> 00:36:45,930
AI programming.

664
00:36:45,930 --> 00:36:47,300
这叫做回溯查找
It's called backtracking
search.

665
00:36:47,300 --> 00:36:57,470

666
00:36:57,470 --> 00:37:03,860
这真得没有必要
And it's really unnecessary.

667
00:37:03,860 --> 00:37:06,550
你看当我想象的这个东西时 我感到疑惑了
You saw me get confused when I
was visualizing this thing.

668
00:37:06,550 --> 00:37:08,550
你也看到了这个复杂性
And you see the complication.

669
00:37:08,550 --> 00:37:10,760
这个东西很难说
This is a complicated
thing to say.

670
00:37:10,760 --> 00:37:12,390
为什么难呢
Why is it complicated?

671
00:37:12,390 --> 00:37:16,190
因为这个很花时间
Its because somehow this program
is too inordinately

672
00:37:16,190 --> 00:37:18,580
concerned with time.

673
00:37:18,580 --> 00:37:19,200
太tmd的久了
It's too much--

674
00:37:19,200 --> 00:37:21,670
我尝试了这个 又尝试了那个
I try this one, and I try this
one, and I go back to the last

675
00:37:21,670 --> 00:37:22,320
然后 我返回到最前面的可能
possibility.

676
00:37:22,320 --> 00:37:24,340
这是一个复杂的事
And that's a complicated
thing.

677
00:37:24,340 --> 00:37:28,590
如果我停止担心思考时间
If I stop worrying about time
so much, then there's a much

678
00:37:28,590 --> 00:37:31,200
我将会得到一个更简单的方法来表述这个
simpler way to describe this.

679
00:37:31,200 --> 00:37:40,320
这个方法是 让我们想象 我有一个有k－1层的树
It says, let's imagine that I
have in my hands the tree down

680
00:37:40,320 --> 00:37:43,400
to k minus 1 levels.

681
00:37:43,400 --> 00:37:50,670
看在第一个k列中 所有的放置皇后的可能性都在我手中了
See, suppose I had in my hands
all possible ways to put down

682
00:37:50,670 --> 00:37:53,560
queens in the first k columns.

683
00:37:53,560 --> 00:37:54,610
假设我有了那个
Suppose I just had that.

684
00:37:54,610 --> 00:37:57,070
让我们不要担心我们如何能搞到它
Let's not worry about
how we get it.

685
00:37:57,070 --> 00:37:59,200
好吧 我怎样进行扩充呢
Well, then, how do
I extend that?

686
00:37:59,200 --> 00:38:01,420
我怎样找到所有在下一个列中放皇后的可能性呢
How do I find all possible ways
to put down queens in the

687
00:38:01,420 --> 00:38:02,480
next column?

688
00:38:02,480 --> 00:38:03,620
这简单
It's really easy.

689
00:38:03,620 --> 00:38:12,210
对于我有的每个位置
For each of these positions I
have, I think about putting

690
00:38:12,210 --> 00:38:16,160
我想把皇后放在每个行中来做下一个东西
down a queen in each row
to make the next thing.

691
00:38:16,160 --> 00:38:18,930
然后 对于每个我放置的 我使用safe来进行filter
And then for each one I put
down, I filter those by the

692
00:38:18,930 --> 00:38:22,080
ones that are safe.

693
00:38:22,080 --> 00:38:24,190
所以代替 把树想成一步步生成的
So instead of thinking about
this tree as generated step by

694
00:38:24,190 --> 00:38:26,860
假设我已经拥有了它
step, suppose I had
it all there.

695
00:38:26,860 --> 00:38:29,680

696
00:38:29,680 --> 00:38:32,990
为了从k-1到k扩充它
And to extend it from level k
minus 1 to level k, I just

697
00:38:32,990 --> 00:38:36,840
我只需要用所有的可能方法来扩充每个东西
need to extend each thing in
all possible ways and only

698
00:38:36,840 --> 00:38:37,800
且只保留安全的东西
keep the ones that are safe.

699
00:38:37,800 --> 00:38:39,300
这将会给我一个k层树
And that will give me
the tree to level k.

700
00:38:39,300 --> 00:38:41,675
这是一个解决八皇后问题的递归策略
And that's a recursive strategy
for solving the eight

701
00:38:41,675 --> 00:38:44,530
queens problem.

702
00:38:44,530 --> 00:38:45,780
好的 我们来看看
All right, well, let's
look at it.

703
00:38:45,780 --> 00:38:50,280

704
00:38:50,280 --> 00:38:54,360
在特定大小的棋盘中解决八皇后问题
To solve the eight queens
problem on a board of some

705
00:38:54,360 --> 00:39:00,390
我们写一个叫填满列的子过程 fill-colums
specified size, we write
a sub-procedure called

706
00:39:00,390 --> 00:39:01,030
fill-columns.

707
00:39:01,030 --> 00:39:04,050
这个过程将会把皇后
Fill-columns is going to
put down queens up

708
00:39:04,050 --> 00:39:06,086
一直放置到列k
through column k.

709
00:39:06,086 --> 00:39:07,700
这里是递归的模式
And here's the pattern
of the recursion.

710
00:39:07,700 --> 00:39:12,990
最后 我将会调用有大小的填充列的方法
I'm going to call fill-columns
with the size eventually.

711
00:39:12,990 --> 00:39:15,630
所以fill-columns说 怎样才能把皇后
So fill-columns says how to put
down queens safely in the

712
00:39:15,630 --> 00:39:19,255
安全的放置在这个棋盘中第一个k列 并且
first k columns of this chess
board with a size number of

713
00:39:19,255 --> 00:39:20,360
rows in it.

714
00:39:20,360 --> 00:39:22,946
如果k＝0 那么我们啥都不用干
If k is equal to 0, well,
then I don't have to

715
00:39:22,946 --> 00:39:23,940
put anything down.

716
00:39:23,940 --> 00:39:26,710
我的结果只是一个空的棋盘
So my solution is just
an empty chess board.

717
00:39:26,710 --> 00:39:28,070
否则 我将会做一些其他的事
Otherwise, I'm going
to do some stuff.

718
00:39:28,070 --> 00:39:30,522
我将会用collect
And I'm going to use collect.

719
00:39:30,522 --> 00:39:31,772
这里有collect
And here's the collect.

720
00:39:31,772 --> 00:39:34,530

721
00:39:34,530 --> 00:39:40,590
我找到了所有在第k-1列中放皇后的方法
I find all ways to put
down queens in the

722
00:39:40,590 --> 00:39:41,910
first k minus 1 columns.

723
00:39:41,910 --> 00:39:43,320
这里只是我设置的
And this was just
what I set for.

724
00:39:43,320 --> 00:39:48,880
想象我有这样的树往下到k-1层
Imagine I have this tree down
to k minus 1 levels.

725
00:39:48,880 --> 00:39:53,230
然后我找到所有尝试行的方法
And then I find all ways of
trying a row, that's just each

726
00:39:53,230 --> 00:39:54,130
那只是每个可能行
of the possible rows.

727
00:39:54,130 --> 00:39:58,040
他是一定尺寸的行 所以那时enumerate 间距
They're size rows, so that's
enumerate interval.

728
00:39:58,040 --> 00:40:03,950
现在我要做的是 我把我将要尝试的新的行和列k用剩下的皇后进行整合
And now what I do is I collect
together the new row I'm going

729
00:40:03,950 --> 00:40:08,950
to try and column k with
the rest of the queens.

730
00:40:08,950 --> 00:40:10,200
我邻接了位置
I adjoin a position.

731
00:40:10,200 --> 00:40:11,290
这是乔治的问题
This is George's problem.

732
00:40:11,290 --> 00:40:13,640
一个邻接的问题和safe差不多
An adjoined position
is like safe.

733
00:40:13,640 --> 00:40:16,530
我们所做的事 是拿一行一列 和剩下的位置 然后做一个新的位置集合
It's a thing that takes a row
and a column and the rest of

734
00:40:16,530 --> 00:40:19,660
the positions and makes a
new position collection.

735
00:40:19,660 --> 00:40:26,230
所以 对于剩下的皇后 我邻接了一个新行和列的位置
So I adjoin a position of a new
row and a new column to

736
00:40:26,230 --> 00:40:30,310
剩下的皇后可以用尝试所有可能性的方法在k－1列来做
the rest of the queens, where
the rest of the queens runs

737
00:40:30,310 --> 00:40:32,870
through all possible ways
of solving the problem

738
00:40:32,870 --> 00:40:34,620
in k minus 1 columns.

739
00:40:34,620 --> 00:40:39,730
新的行运行了所有行的可能性
And the new row runs through all
possible rows such that it

740
00:40:39,730 --> 00:40:43,240
使得放在这里安全
was safe to put one there.

741
00:40:43,240 --> 00:40:46,500
这就是整个程序了
And that's the whole program.

742
00:40:46,500 --> 00:40:49,840
这是整个过程
There's the whole procedure.

743
00:40:49,840 --> 00:40:51,990
不仅仅是这样 这不仅仅解决八皇后问题
Not only that, that doesn't just
solve the eight queens

744
00:40:51,990 --> 00:40:56,010
还顺手给出了八皇后问题的所有解
problem, it gives you
all solutions to the

745
00:40:56,010 --> 00:40:56,680
eight queens problem.

746
00:40:56,680 --> 00:40:58,480
当你搞定了 你就有一个流
When you're done, you
have a stream.

747
00:40:58,480 --> 00:41:00,650
流中的元素是解决这个问题的所有可能性
And the elements of that stream
are all possible ways

748
00:41:00,650 --> 00:41:01,900
of solving that problem.

749
00:41:01,900 --> 00:41:05,310

750
00:41:05,310 --> 00:41:06,260
为什么这个更加简单呢
Why is that simpler?

751
00:41:06,260 --> 00:41:10,170
好吧 我们抛出了整个想法 这个想法是一些在时间中发生的，有状态的过程
Well, we threw away the whole
idea that this is some process

752
00:41:10,170 --> 00:41:12,720
that happens in time
with state.

753
00:41:12,720 --> 00:41:14,420
并且 我们只会说 这是东西的整个集合
And we just said it's a whole
collection of stuff.

754
00:41:14,420 --> 00:41:18,260
这就是更加简单的原因
And that's why it's simpler.

755
00:41:18,260 --> 00:41:20,110
我们改变了我们的观念
We've changed our view.

756
00:41:20,110 --> 00:41:22,820
记住我们今天开始的地方
Remember, that's where
we started today.

757
00:41:22,820 --> 00:41:26,230
我们搞变了我们的这我们尝试去建模的东西是什么的观念
We've changed our view of what
it is we're trying to model.

758
00:41:26,230 --> 00:41:30,570
我们停止对随着时间的发展的，并有过程和状态的物体进行建模
we stop modeling things that
evolve in time and have steps

759
00:41:30,570 --> 00:41:31,750
and have state.

760
00:41:31,750 --> 00:41:33,990
作为替代 我们尽力给像粉笔飞行这样的全局的东西进行建模
And instead, we're trying to
model this global thing like

761
00:41:33,990 --> 00:41:37,950
the whole flight of the
chalk, rather than its

762
00:41:37,950 --> 00:41:40,750
而不是它们的在每个时间的状态
state at each instant.

763
00:41:40,750 --> 00:41:42,000
有神马问题
Any questions?

764
00:41:42,000 --> 00:41:43,810

765
00:41:43,810 --> 00:41:46,190
在我看来 回溯法将会找到它能找到的第一个解
AUDIENCE: It looks to me like
backtracking would be

766
00:41:46,190 --> 00:41:49,970
searching for the first solution
it can find, whereas

767
00:41:49,970 --> 00:41:54,030
但是这个递归搜索将会查找所有的解
this recursive search would be
looking for all solutions.

768
00:41:54,030 --> 00:41:58,090
而且看起来 如果你有足够大的空间去查找
And it seems that if you have a
large enough area to search,

769
00:41:58,090 --> 00:42:01,360
第二个将会变得不可能
that the second is going
to become impossible.

770
00:42:01,360 --> 00:42:07,610
好的 这个问题的解就是我们剩下这节课所要讲的内容
PROFESSOR: OK, the answer to
that question is the whole

771
00:42:07,610 --> 00:42:08,570
rest of this lecture.

772
00:42:08,570 --> 00:42:10,540
这是一个好问题
It's exactly the
right question.

773
00:42:10,540 --> 00:42:13,522

774
00:42:13,522 --> 00:42:15,540
如果你不尝试提前预见到后面的课
And without trying to anticipate
the lecture too

775
00:42:15,540 --> 00:42:19,910
你应该开始怀疑这个点
much, you should start being
suspicious at this point, and

776
00:42:19,910 --> 00:42:22,220
这个的确是令人怀疑的
exactly those kinds
of suspicions.

777
00:42:22,220 --> 00:42:24,830
这是好的 但是这不是非常的不方便吗
It's wonderful, but isn't it
so terribly inefficient?

778
00:42:24,830 --> 00:42:28,100
这是我们现在进行的
That's where we're going.

779
00:42:28,100 --> 00:42:30,020
所以我现在不说 等等再揭晓答案
So I won't answer now, but
I'll answer later.

780
00:42:30,020 --> 00:42:33,350

781
00:42:33,350 --> 00:42:34,600
让我们休息一下
OK, let's take a break.

782
00:42:34,600 --> 00:43:29,650

783
00:43:29,650 --> 00:43:35,600
现在你应该开始怀疑了
Well, by now you should be
starting to get suspicious.

784
00:43:35,600 --> 00:43:41,450
看 我已经展示了这个简单优雅的将程序放在一起的方法
See, I've showed your this
simple, elegant way of putting

785
00:43:41,450 --> 00:43:46,440
不像这些另外的累积奇数的传统方法或者算奇数的斐波那契数
programs together, very unlike
these other traditional

786
00:43:46,440 --> 00:43:50,490

programs that sum the odd
squares or compute the odd

787
00:43:50,490 --> 00:43:53,740
Fibonacci numbers.

788
00:43:53,740 --> 00:43:57,080
也不像这些混合enumerator filter 和accumulator的方法
Very unlike these programs that
mix up the enumerator and

789
00:43:57,080 --> 00:44:00,440
the filter and the
accumulator.

790
00:44:00,440 --> 00:44:04,770
通过混合 我们没有所有这些美妙的概念上的这些流元件的优点
And by mixing it up, we don't
have all of these wonderful

791
00:44:04,770 --> 00:44:07,990
conceptual advantages of these
streams pieces, these

792
00:44:07,990 --> 00:44:09,840
这些为了把许多程序整合在一起的美妙的混合和匹配部件
wonderful mix and match
components for putting

793
00:44:09,840 --> 00:44:13,800
together lots and lots
of programs.

794
00:44:13,800 --> 00:44:15,810
再另一方面 你能见到的所有程序大部分都和这个屌丝程序一样
On the other hand, most of the
programs you've seen look like

795
00:44:15,810 --> 00:44:18,340
these ugly ones.

796
00:44:18,340 --> 00:44:19,460
为什么呢
Why's that?

797
00:44:19,460 --> 00:44:23,705
计算机科学家们可能没有注意到如果你仅仅做了这个事
Can it possibly be that computer
scientists are so

798
00:44:23,705 --> 00:44:28,370
obtuse that they don't notice
that if you'd merely did this

799
00:44:28,370 --> 00:44:33,620
然后你可以获得这个这个程序的优雅性吗
thing, then you can get this
great programming elegance?

800
00:44:33,620 --> 00:44:36,760
这里得有一个catch
There's got to be a catch.

801
00:44:36,760 --> 00:44:39,510
并且事实上 我们可以很容易看到 什么是catch
And it's actually pretty easy
to see what the catch is.

802
00:44:39,510 --> 00:44:42,030
让我们想一下下面的问题
Let's think about the
following problem.

803
00:44:42,030 --> 00:44:47,510
假设我告诉你找到在10000－一百万里第二个素数
Suppose I tell you to find the
second prime between 10,000

804
00:44:47,510 --> 00:44:51,020
或者如果你的计算机足够强大
and 1 million, or if your
computer's larger, say between

805
00:44:51,020 --> 00:44:54,105
比如说10000到1000亿
10,000 and 100 billion,
or something.

806
00:44:54,105 --> 00:44:55,550
然后你说 这很容易
And you say, oh, that's easy.

807
00:44:55,550 --> 00:44:57,080
我能用流来搞定
I can do that with a stream.

808
00:44:57,080 --> 00:45:01,530
我需要做的就是枚举从10000到1百万
All I do is I enumerate
the interval

809
00:45:01,530 --> 00:45:04,160
from 10,000 to 1 million.

810
00:45:04,160 --> 00:45:06,800
然后我得到了所有从10000到1百万中挑选的数字
So I get all those integers
from 10,000 to 1 million.

811
00:45:06,800 --> 00:45:10,520
我们为了素数性对它们进行filter操作 然后检测所有的数 看看是不是素数
I filter them for prime-ness, so
test all of them and see if

812
00:45:10,520 --> 00:45:11,762
they're prime.

813
00:45:11,762 --> 00:45:13,170
然后我拿出第二个元素
And I take the second element.

814
00:45:13,170 --> 00:45:16,130
这是尾部的第一个
That's the head of the tail.

815
00:45:16,130 --> 00:45:17,380
这就非常搞笑了
Well, that's clearly
pretty ridiculous.

816
00:45:17,380 --> 00:45:21,660

817
00:45:21,660 --> 00:45:24,620
在一开始我们甚至没有在机器中有存放整数的地方
We'd not even have room in the
machine to store the integers

818
00:45:24,620 --> 00:45:27,040
更不用说来检测他们了
in the first place, much
less to test them.

819
00:45:27,040 --> 00:45:29,810
然后我只要第二个
And then I only want
the second one.

820
00:45:29,810 --> 00:45:36,500
这种传统的编程风格的威力也有它的弱点
See, the power of this
traditional programming style

821
00:45:36,500 --> 00:45:39,860
is exactly its weakness, that
we're mixing up the

822
00:45:39,860 --> 00:45:45,090
那是我们混合了enumerating testing accumulating
enumerating and the testing
and the accumulating.

823
00:45:45,090 --> 00:45:46,670
所以我们不做所有的事
So we don't do it all.

824
00:45:46,670 --> 00:45:52,580
所以使它在概念上更加丑陋的这个东西使它更加有效
So the very thing that makes
it conceptually ugly is the

825
00:45:52,580 --> 00:45:55,210
very thing that makes
it efficient.

826
00:45:55,210 --> 00:45:57,800
是这样混合的
It's this mixing up.

827
00:45:57,800 --> 00:45:59,840
所以这看起来我们在早上讲的所有的这些东西只会使你们疑惑
So it seems that all I've done
this morning so far is just

828
00:45:59,840 --> 00:46:00,420
confuse you.

829
00:46:00,420 --> 00:46:02,930
我展示给你们这个优雅的编程方法可能可以工作
I showed you this wonderful
way that programming might

830
00:46:02,930 --> 00:46:05,840
除了那个不行
work, except that it doesn't.

831
00:46:05,840 --> 00:46:09,040
好吧 这里是美好的事发生的地方
Well, here's where the wonderful
thing happens.

832
00:46:09,040 --> 00:46:13,210
在这个游戏里 我门真正可以吃蛋糕 并吃它
It turns out in this game that
we really can have our cake

833
00:46:13,210 --> 00:46:14,870
and eat it too.

834
00:46:14,870 --> 00:46:20,280
我的意思是 我们真的可以完全像我写和安排的那样使用流编程
And what I mean by that is
that we really can write

835
00:46:20,280 --> 00:46:24,210
stream programs exactly like the
ones I wrote and arrange

836
00:46:24,210 --> 00:46:28,830
当机器真正运行
things so that when the machine
actually runs, it's as

837
00:46:28,830 --> 00:46:31,690
它运行起来和混合generation和test传统编程风格一样有效率
efficient as running this
traditional programming style

838
00:46:31,690 --> 00:46:36,310
that mixes up the generation
and the test.

839
00:46:36,310 --> 00:46:40,770
好吧 那听起来很神奇
Well, that sounds
pretty magic.

840
00:46:40,770 --> 00:46:43,690
这个的关键是流不是列表
The key to this is that
streams are not lists.

841
00:46:43,690 --> 00:46:48,090

842
00:46:48,090 --> 00:46:50,070
等等 我们将会小心的看到
We'll see this carefully in a
second, but for now, let's

843
00:46:50,070 --> 00:46:52,115
但现在 让我们再次看看幻灯片
take a look at that
slide again.

844
00:46:52,115 --> 00:46:55,060
你应该有的信号处理系统的图片是
The image you should have here
of this signal processing

845
00:46:55,060 --> 00:47:00,940
system is that what's going to
happen is there's this box

846
00:47:00,940 --> 00:47:05,360
在这里有一个盒子里面有一个整数
that has the integers
sitting in it.

847
00:47:05,360 --> 00:47:08,680
这里有这个filter来连接
And there's this filter that's
connected to it and it's

848
00:47:08,680 --> 00:47:10,940
并且这个揪住了它们
tugging on them.

849
00:47:10,940 --> 00:47:13,680
然后 那里有揪住这个东西的某人
And then there's someone who's
tugging on this stuff saying

850
00:47:13,680 --> 00:47:16,790
说 那个从filter中出来
what comes out of the filter.

851
00:47:16,790 --> 00:47:19,630
你应该有的图片是 
And the image you should have
is that someone says, well,

852
00:47:19,630 --> 00:47:24,590
某些人说 好吧 第一个素数是什么
what's the first prime, and
tugs on this filter.

853
00:47:24,590 --> 00:47:28,020
并且这个filter揪住了整数
And the filter tugs
on the integers.

854
00:47:28,020 --> 00:47:29,830
并且你只看这些
And you look only at that much,
and then say, oh, I

855
00:47:29,830 --> 00:47:30,930
然后说 噢 我真的想要第二个
really wanted the second one.

856
00:47:30,930 --> 00:47:33,710
第二个素数是什么
What's the second prime?

857
00:47:33,710 --> 00:47:37,730
没有计算完成 除了当你揪住那些东西
And that no computation gets
done except when you tug on

858
00:47:37,730 --> 00:47:40,500
these things.

859
00:47:40,500 --> 00:47:41,410
让我们再来试试
Let me try that again.

860
00:47:41,410 --> 00:47:43,815
这是一个小的设备
This is a little device.

861
00:47:43,815 --> 00:47:46,400
这是一个由Eric Grimson 发明的小型的流机器
This is a little stream machine
invented by Eric

862
00:47:46,400 --> 00:47:49,830
这个大神曾经在麻省理工教这门课
Grimson who's been teaching
this course at MIT.

863
00:47:49,830 --> 00:47:52,940
并且这里的图片是一个东西的流
And the image is here's a stream
of stuff, like a whole

864
00:47:52,940 --> 00:47:54,780
像一串整数
bunch of the integers.

865
00:47:54,780 --> 00:47:58,700
并且这里有一些处理中的元素
And here's some processing
elements.

866
00:47:58,700 --> 00:48:02,600
并且 如果说 资格赛map的filter的filter或者一些东西
And if, say, it's filter of
filter of map, or something.

867
00:48:02,600 --> 00:48:05,570

868
00:48:05,570 --> 00:48:08,760
并且如果我真的尝试用流作为列表实现
And if I really tried to
implement that with streams as

869
00:48:08,760 --> 00:48:11,520
我想说得是 我已有了这个列表
lists, what I'd say is, well,
I've got this list of things,

870
00:48:11,520 --> 00:48:12,670
现在 我开始使用第一个filter
and now I do the first filter.

871
00:48:12,670 --> 00:48:14,070
做所有的这些处理
So do all this processing.

872
00:48:14,070 --> 00:48:18,570
并且我拿这个来一直进行不断处理
And I take this and I process
and I process and I process

873
00:48:18,570 --> 00:48:19,610
and I process.

874
00:48:19,610 --> 00:48:21,910
现在 我已经得到了这个新的流
And now I'm got this
new stream.

875
00:48:21,910 --> 00:48:24,070
现在我把这结果放在我手上某处
Now I take that result
in my hand someplace.

876
00:48:24,070 --> 00:48:25,260
并且把第二个和那个接通
And I put that through
the second one.

877
00:48:25,260 --> 00:48:28,110
然后 我处理整个东西
And I process the whole thing.

878
00:48:28,110 --> 00:48:29,510
这个有一个新的流
And there's this new stream.

879
00:48:29,510 --> 00:48:32,130

880
00:48:32,130 --> 00:48:35,230
然后 我拿那个结果  并且我把它和这个用相同方法接通
And then I take the result and
I put it all the way through

881
00:48:35,230 --> 00:48:36,360
this one the same way.

882
00:48:36,360 --> 00:48:41,760
这些将会是流编程将会发生的
That's what would happen to
these stream programs if

883
00:48:41,760 --> 00:48:43,860
如果流只是一个列表
streams were just lists.

884
00:48:43,860 --> 00:48:46,065
但是实际上 流不是列表 这只是流
But in fact, streams aren't
lists, they're streams. And

885
00:48:46,065 --> 00:48:47,240
你将会有的图是一种有点更像这个的东西
the image you should have
is something a little

886
00:48:47,240 --> 00:48:50,230
bit more like this.

887

00:48:50,230 --> 00:48:55,880
我通过数据把这些小玩意连接
I've got these gadgets connected
up by this data

888
00:48:55,880 --> 00:48:57,130
那个将会从它们那里流出
that's flowing out of them.

889
00:48:57,130 --> 00:48:59,960

890
00:48:59,960 --> 00:49:04,190
这里是我原始的流的来源
And here's my original source
of the streams. It might be

891
00:49:04,190 --> 00:49:05,980
这可能开始生成整数
starting to generate
the integers.

892
00:49:05,980 --> 00:49:07,580
现在 如果我想要一个结果 会发生什么呢
And now, what happens
if I want a result?

893
00:49:07,580 --> 00:49:10,200
我把在这里最后的东西揪住
I tug on the end here.

894
00:49:10,200 --> 00:49:13,090
这个元素说 挖 我需要更多的数据
And this element says, gee,
I need some more data.

895
00:49:13,090 --> 00:49:15,830
所以 这个到这里 并且揪住那个
So this one comes here
and tugs on that one.

896
00:49:15,830 --> 00:49:17,890
并且它说 挖 我需要更多的数据
And it says, gee, I need
some more data.

897
00:49:17,890 --> 00:49:19,960
并且这个揪住了这个可能是一个filter的东西 
And this one tugs on this
thing, which might be a

898
00:49:19,960 --> 00:49:21,640
并且说 挖 我需要更多的数据
filter, and says, gee, I
need some more data.

899
00:49:21,640 --> 00:49:24,755
并且只当 这些在这里的最后的东西和我揪住一样多时
And only as much of this thing
at the end here gets generated

900
00:49:24,755 --> 00:49:25,780
as I tugged.

901
00:49:25,780 --> 00:49:28,030
并且只当 这些通过处理单元的东西和我抓得一样多时
And only as much of this stuff
goes through the processing

902
00:49:28,030 --> 00:49:30,760
units as I'm pulling
on the end I need.

903
00:49:30,760 --> 00:49:33,720
那才是你应该有的画面
That's the image you should have
of the difference between

904
00:49:33,720 --> 00:49:36,580
实现你到底该怎样做的区别
implementing what we're actually
going to do and if

905
00:49:36,580 --> 00:49:37,830
并且如果流是列表的话
streams were lists.

906
00:49:37,830 --> 00:49:40,600

907
00:49:40,600 --> 00:49:42,430
好吧 我们怎样做这些事
Well, how do we make
this thing?

908
00:49:42,430 --> 00:49:43,400
我希望你能有这些图片
I hope you have the image.

909
00:49:43,400 --> 00:49:44,947
窍门是怎样做它
The trick is how to make it.

910
00:49:44,947 --> 00:49:47,930

911
00:49:47,930 --> 00:49:52,080
我们想要处理这个流 将它变成数据结构递增计算它本身
We want to arrange for a stream
to be a data structure

912
00:49:52,080 --> 00:49:55,670
that computes itself
incrementally, an on-demand

913
00:49:55,670 --> 00:49:56,920
按需数据结构
data structure.

914
00:49:56,920 --> 00:49:59,220

915
00:49:59,220 --> 00:50:02,700
并且基本思想是 
And the basic idea is, again,
one of the very basic ideas

916
00:50:02,700 --> 00:50:04,490
再说一下 这个整个课的基本思想是
that we're seeing throughout
the whole course.

917
00:50:04,490 --> 00:50:07,440
那是 在程序和数据之间没有严格的界限
And that is that there's not
a firm distinction between

918
00:50:07,440 --> 00:50:09,240
programs and data.

919
00:50:09,240 --> 00:50:12,260
流将会同步这些数据
So what a stream is going to be
is simultaneously this data

920
00:50:12,260 --> 00:50:15,270
像这个树的叶子的流
structure that you think of,
like the stream of the leaves

921
00:50:15,270 --> 00:50:16,810
of this tree.

922
00:50:16,810 --> 00:50:18,880
但同时 这将会变成聪明的并有计算方法在其中的过程
But at the same time, it's
going to be a very clever

923
00:50:18,880 --> 00:50:23,550
procedure that has the method
of computing in it.

924
00:50:23,550 --> 00:50:25,930
好吧 让我们来试试这个
Well, let me try this.

925
00:50:25,930 --> 00:50:28,460
这个结果是 我们不要更加多的原理
It's going to turn out that we
don't need any more mechanism.

926
00:50:28,460 --> 00:50:31,150
我们已经从一个事实中有了我们需要的所有东西
We already have everything we
need simply from the fact that

927
00:50:31,150 --> 00:50:32,770
我们知道如何处理作为第一级对象的过程
we know how to handle
procedures

928
00:50:32,770 --> 00:50:35,460
as first-class objects.

929
00:50:35,460 --> 00:50:36,880
好吧 让我们看下这个key
Well, let's go back
to the key.

930
00:50:36,880 --> 00:50:39,030
关键是 记住 我们有这些操作
The key is, remember, we
had these operations.

931
00:50:39,030 --> 00:50:48,080
cons流 头和尾
CONS-stream and head and tail.

932
00:50:48,080 --> 00:50:51,580
当我开始 我说 你可以将这个想象成cons 
When I started, I said you can
think about this as CONS and

933
00:50:51,580 --> 00:50:53,340
把那个想象成car 把那个相信成cdr
think about this as CAR and
think about that as

934
00:50:53,340 --> 00:50:55,080
但这不是
CDR, but it's not.

935
00:50:55,080 --> 00:50:57,550
现在 让我们看看这些到底是什么
Now, let's look at what
they really are.

936
00:50:57,550 --> 00:51:09,360
x和y的cons流将变成接下来东西的缩写
Well, CONS-stream of x and y is
going to be an abbreviation

937
00:51:09,360 --> 00:51:19,540
for the following thing.

938
00:51:19,540 --> 00:51:24,470
cons产生一个序对 普通的cons
CONS form a pair, ordinary CONS,
of x to a thing called

939
00:51:24,470 --> 00:51:28,000
由一个x和一个delay y构成
delay of y.

940
00:51:28,000 --> 00:51:31,188

941
00:51:31,188 --> 00:51:34,670
在我解释那个之前，让我们来写剩余的部分
And before I explain that, let
me go and write the rest. The

942
00:51:34,670 --> 00:51:39,790
流的头将会变成car
head of a stream is going
to be just the CAR.

943
00:51:39,790 --> 00:51:42,380

944
00:51:42,380 --> 00:51:47,610
流的尾部将会变成一种叫 force 流的cdr
And the tail of a stream is
going to be a thing called

945
00:51:47,610 --> 00:51:56,120
force the CDR of the stream.

946
00:51:56,120 --> 00:51:58,060
现在让我解释这些
Now let me explain this.

947
00:51:58,060 --> 00:52:01,420
延时将会变成一件特别神奇的事
Delay is going to be a
special magic thing.

948
00:52:01,420 --> 00:52:06,240
延时做的是拿一个表达式产生一个计算当你要求表达式的承诺
What delay does is take an
expression and produce a

949
00:52:06,240 --> 00:52:08,380
promise to compute
that expression

950
00:52:08,380 --> 00:52:10,600
when you ask for it.

951
00:52:10,600 --> 00:52:11,980
在这里不做任何计算
It doesn't do any computation
here.

952
00:52:11,980 --> 00:52:14,820
这仅仅给你一个延时
It just gives you
a rain check.

953
00:52:14,820 --> 00:52:17,110
这产生了一个承诺
It produces a promise.

954
00:52:17,110 --> 00:52:23,280
cons流说 我将做一个x
And CONS-stream says I'm going
to put together in a pair x

955
00:52:23,280 --> 00:52:25,360
和一个承诺的序对来计算y
and a promise to compute y.

956
00:52:25,360 --> 00:52:28,230

957
00:52:28,230 --> 00:52:30,200
现在 如果你想要头 这只是序对里的car
Now, if I want the head, that's
just the CAR that I put

958
00:52:30,200 --> 00:52:31,840
in the pair.

959
00:52:31,840 --> 00:52:34,350
这个的关键是 尾将会在承诺中force调用
And the key is that the
tail is going to be--

960
00:52:34,350 --> 00:52:39,110
force calls in that promise.

961
00:52:39,110 --> 00:52:43,690
尾说 好吧 取得这个承诺  然后 在那个承诺中调用
Tail says, well, take
that promise and now

962
00:52:43,690 --> 00:52:44,610
call in that promise.

963
00:52:44,610 --> 00:52:47,430
然后我们计算那个东西
And then we compute
that thing.

964
00:52:47,430 --> 00:52:48,740
这就是工作的方法
That's how this is
going to work.

965
00:52:48,740 --> 00:52:51,550
那个就是cons流 头 和 尾了
That's what CONS-stream, head,
and tail really are.

966
00:52:51,550 --> 00:52:54,196

967
00:52:54,196 --> 00:52:55,570
现在 让我们来看看这个怎样工作
Now, let's see how this works.

968
00:52:55,570 --> 00:52:58,410
我们将会非常小心地过一遍
And we'll go through this
fairly carefully.

969
00:52:58,410 --> 00:53:01,990
在这个 计算在一万和一百万之间的第二个素数 的例子中 我们将会看到这是如何工作的
We're going to see how this
works in this example of

970
00:53:01,990 --> 00:53:08,650
computing the second prime
between 10,000 and a million.

971

00:53:08,650 --> 00:53:11,610
ok 让我们开始    我们有这个表达式
OK, so we start off and we
have this expression.

972
00:53:11,610 --> 00:53:15,820

973
00:53:15,820 --> 00:53:20,380
第二个素数－－ 为在一万和一百万的整数素数性进行filtering
The second prime-- the head of
the tail of the result of

974
00:53:20,380 --> 00:53:24,060
filtering for primality
the integers between

975
00:53:24,060 --> 00:53:26,710
10,000 and 1 million.

976
00:53:26,710 --> 00:53:28,400
现在 那是什么
Now, what is that?

977
00:53:28,400 --> 00:53:35,790
这是一万和一百万之间的间距
What that is, that interval
between 10,000 and 1 million,

978
00:53:35,790 --> 00:53:37,480
好吧 如果你探查enumerate的间距
well, if you trace through
enumerate interval, there

979
00:53:37,480 --> 00:53:40,250
这里建立了一个cons流
builds a CONS-stream.

980
00:53:40,250 --> 00:53:45,880
并且 cons流是10000的cons的许诺来计算10001到一百万
And the CONS-stream is the CONS
of 10,000 to a promise to

981
00:53:45,880 --> 00:53:54,480
compute the integers between
10,001 and 1 million.

982
00:53:54,480 --> 00:53:55,750
所以 那就是这个表达式了
So that's what this
expression is.

983
00:53:55,750 --> 00:53:57,640
这里 我使用代换模型
Here I'm using the substitution
model.

984
00:53:57,640 --> 00:53:59,690
我们能使用代换模型的原因是因为我们没有副作用和状态
And we can use the substitution
model because we

985
00:53:59,690 --> 00:54:01,010
don't have side effects
and state.

986
00:54:01,010 --> 00:54:04,270

987
00:54:04,270 --> 00:54:07,860
所以 我们有一个10000的cons的许诺来计算剩余的整数
So I have CONS of 10,000 to a
promise to compute the rest of

988
00:54:07,860 --> 00:54:08,380
the integers.

989
00:54:08,380 --> 00:54:09,850
所以到现在为止只有一个整数得到了enumerated
So only one integer, so
far, got enumerated.

990
00:54:09,850 --> 00:54:14,380

991
00:54:14,380 --> 00:54:16,580
好的 我将会为了素数性来filter这些东西
Well, I'm going to filter that
thing for primality.

992
00:54:16,580 --> 00:54:19,900

993
00:54:19,900 --> 00:54:22,360
再次 你将会回去看过了filter代码
Again, you go back and look
at the filter code.

994
00:54:22,360 --> 00:54:25,460
filter首先测试头
What the filter will first
do is test the head.

995
00:54:25,460 --> 00:54:31,580
所以在这种情况下 filter将会测试一万
So in this case, the filter will
test 10,000 and say, oh,

996
00:54:31,580 --> 00:54:33,500
然后说一万不是素数
10,000's not prime.

997
00:54:33,500 --> 00:54:36,260
所以我不得不递归的过滤尾
Therefore, what I have
to do recursively

998
00:54:36,260 --> 00:54:39,220
is filter the tail.

999
00:54:39,220 --> 00:54:42,550
这个是什么的尾呢 好吧 这是这个有许诺序对的尾序对的尾
And what's the tail of it, well,
that's the tail of this

1000
00:54:42,550 --> 00:54:46,340
pair with a promise in it.

1001
00:54:46,340 --> 00:54:49,680
尾进来了 然后说 好吧 我将要迫使那个
Tail now comes in and says,
well, I'm going to force that.

1002
00:54:49,680 --> 00:54:53,790
我将要迫使那个许诺 它的意思是
I'm going to force that promise,
which means now I'm

1003
00:54:53,790 --> 00:55:00,880
现在我将要计算10001到一百万之中的整数
going to compute the integers
between 10,001 and 1 million.

1004
00:55:00,880 --> 00:55:02,970
好的 所以这个filter现在着眼于那里
OK, so this filter now
is looking at that.

1005
00:55:02,970 --> 00:55:07,810

1006
00:55:07,810 --> 00:55:10,100
那个枚举了它本身 好吧 现在我们回到原始枚举情况
That enumerate itself, well, now
we're back in the original

1007
00:55:10,100 --> 00:55:11,960
enumerate situation.

1008
00:55:11,960 --> 00:55:16,920
enumerate是第一个东西的cons 10001
The enumerate is the CONS of the
first thing, 10,001, onto

1009
00:55:16,920 --> 00:55:19,740
映射到一个许诺来计算剩下的
a promise to compute the rest.

1010
00:55:19,740 --> 00:55:23,060
所以 现在原始的filter将会着眼于10001
So now the primality filter is
going to go look at 10,001.

1011
00:55:23,060 --> 00:55:25,120
这将要决定它像那个还是不像
It's going to decide if
it likes that or not.

1012
00:55:25,120 --> 00:55:27,550
这个结果是10001不是素数
It turns out 10,001
isn't prime.

1013
00:55:27,550 --> 00:55:29,610
所以我将会再次连续不断的进行force
So it'll force it again
and again and again.

1014
00:55:29,610 --> 00:55:32,920

1015
00:55:32,920 --> 00:55:37,100
最后 我觉得第一个素数会是10009
And finally, I think the first
prime it hits is 10,009.

1016
00:55:37,100 --> 00:55:40,465
然后 在这个点上 它将会停止
And at that point, it'll stop.

1017
00:55:40,465 --> 00:55:42,500
那个将会变成第一个素数
And that will be the first
prime, and then eventually,

1018
00:55:42,500 --> 00:55:45,240
最后 这将需要第二个素数
it'll need the second prime.

1019
00:55:45,240 --> 00:55:47,030
所以在那个点上
So at that point, it
will go again.

1020
00:55:47,030 --> 00:55:51,880
所以你会发现生成的不会比你实际需要的多
So you see what happens is that
no more gets generated

1021
00:55:51,880 --> 00:55:53,130
than you actually need.

1022
00:55:53,130 --> 00:55:56,690

1023
00:55:56,690 --> 00:56:00,060
那个enumerator将不会比filter生成更多整数
That enumerator is not going to
generate any more integers

1024
00:56:00,060 --> 00:56:02,410
引入东西来检测素数性
than the filter asks it for as
it's pulling in things to

1025
00:56:02,410 --> 00:56:04,930
check for primality.

1026
00:56:04,930 --> 00:56:07,290
并且这个filter将不会生成比你要求更多的东西
And the filter is not going to
generate any more stuff than

1027
00:56:07,290 --> 00:56:11,255
这是尾的头
you ask it for, which is
the head of the tail.

1028
00:56:11,255 --> 00:56:17,180
你看 我们把混合的生成和测试放入计算机
You see, what's happened is
we've put that mixing of

1029
00:56:17,180 --> 00:56:20,130
并且检测在电脑中究竟发生了什么
generation and test into what
actually happens in the

1030
00:56:20,130 --> 00:56:24,250
虽然 那个从我们的程序看来不是很明显
computer, even though that's
not apparently what's

1031
00:56:24,250 --> 00:56:28,160
happening from looking
at our programs.

1032
00:56:28,160 --> 00:56:30,230
好的 那看起来简单
OK, well, that seemed easy.

1033
00:56:30,230 --> 00:56:33,326
所有的这些机制会被放入这个神奇的delay中
All of this mechanism got put
into this magic delay.

1034
00:56:33,326 --> 00:56:36,900
所以 你会说 那将会是有魔法的地方
So you're saying, gee, that must
be where the magic is.

1035
00:56:36,900 --> 00:56:39,070
但是看这里也没有魔法
But see there's no magic
there either.

1036
00:56:39,070 --> 00:56:40,610
你知道什么是delay
You know what delay is.

1037
00:56:40,610 --> 00:56:50,040
在一些表达式上的delay只是一个缩略词
Delay on some expression is
just an abbreviation for--

1038
00:56:50,040 --> 00:56:53,400

1039
00:56:53,400 --> 00:56:56,490
好吧 计算表达式的primise是什么
well, what's a promise to
compute an expression?

1040
00:56:56,490 --> 00:57:00,700
lambda of nil 一个没有参数的过程
Lambda of nil, procedure of no
arguments, which is that

1041
00:57:00,700 --> 00:57:03,000
就是那个表达式
expression.

1042
00:57:03,000 --> 00:57:03,930
那就是这个过程
That's what a procedure is.

1043
00:57:03,930 --> 00:57:06,050
我将会计算一个表达式
It says I'm going to compute
an expression.

1044
00:57:06,050 --> 00:57:07,460
什么是force
What's force?

1045
00:57:07,460 --> 00:57:10,800
我怎么着手一个许诺
How do I take up a promise?

1046
00:57:10,800 --> 00:57:15,890
好的 一些过程的force   一个许诺 只是运行它
Well, force of some procedure,
a promise, is just run it.

1047
00:57:15,890 --> 00:57:18,710

1048
00:57:18,710 --> 00:57:20,120
做好了
Done.

1049
00:57:20,120 --> 00:57:23,580
所以 这里完全没有魔法
So there's no magic
there at all.

1050
00:57:23,580 --> 00:57:26,440
好吧 我们做了啥
Well, what have we done?

1051
00:57:26,440 --> 00:57:29,510
我们说 老风格
We said the old style,
traditional style of

1052
00:57:29,510 --> 00:57:30,960
传统的编程风格将会是更加有效的
programming is more efficient.

1053
00:57:30,960 --> 00:57:35,260
流是更加的清晰明白的
And the stream thing is
more perspicuous.

1054
00:57:35,260 --> 00:57:40,070
并且我们使用delay设法使流过程运行的像其他的过程一样
And we managed to make the
stream procedures run like the

1055
00:57:40,070 --> 00:57:43,350
other procedures
by using delay.

1056
00:57:43,350 --> 00:57:46,880
delay为我们做的事是在我们从发生在机器中的真实顺序中程序事务上表面的顺序上进行解耦
And the thing that delay did
for us was to de-couple the

1057
00:57:46,880 --> 00:57:52,150
apparent order of events in our
programs from the actual

1058
00:57:52,150 --> 00:57:54,440
order of events that happened
in the machine.

1059
00:57:54,440 --> 00:57:56,540
那就是delay所做的
That's really what
delay is doing.

1060
00:57:56,540 --> 00:57:58,290
就是这样
That's exactly the
whole point.

1061
00:57:58,290 --> 00:58:04,720
我们放弃了当我们的过程开始运行的想法
We've given up the idea that our
procedures, as they run,

1062
00:58:04,720 --> 00:58:09,182
或者 当我们看到它们 映射一些时间的清晰概念
or as we look at them, mirror
some clear notion of time.

1063
00:58:09,182 --> 00:58:12,960
然后 通过放弃那个 我们给delay自由来处理在计算事件的顺序
And by giving that up, we give
delay the freedom to arrange

1064
00:58:12,960 --> 00:58:16,690
the order of events in the
computation the way it likes.

1065
00:58:16,690 --> 00:58:17,610
整个思想就是这样
That's the whole idea.

1066
00:58:17,610 --> 00:58:20,640
我们de-couple在我们程序上事件表面上的顺序
We de-couple the apparent
order of events in our

1067
00:58:20,640 --> 00:58:24,200
programs from the actual order
of events in the computer.

1068
00:58:24,200 --> 00:58:25,770
好的 这里还有一个细节
OK, well there's one
more detail.

1069
00:58:25,770 --> 00:58:27,750
这是是技术上的细节
It's just a technical detail,
but it's actually

1070
00:58:27,750 --> 00:58:29,730
但是 这个其实是很重要的
an important one.

1071
00:58:29,730 --> 00:58:32,190
当你运行了这些递归循环的程序
As you run through these
recursive programs unwinding,

1072
00:58:32,190 --> 00:58:35,360
你将会看到很多像这个的东西 像尾部的尾部的尾部
you'll see a lot of things that
look like tail of the

1073
00:58:35,360 --> 00:58:39,320
tail of the tail.

1074
00:58:39,320 --> 00:58:41,840
当我使用consing往下到一个流  这将是会发生的事
That's the kind of thing that
would happen as I go CONSing

1075
00:58:41,840 --> 00:58:43,860
down a stream all the way.

1076
00:58:43,860 --> 00:58:47,170
并且如果 我每次做那个事
And if each time I'm doing that,
each time to compute a

1077
00:58:47,170 --> 00:58:51,830
每次计算尾部 我求出一个过程的值
tail, I evaluate a procedure
which then has to go

1078
00:58:51,830 --> 00:58:54,270
然后 不得不再次计算那个尾部 然后再次计算那个尾部
re-compute its tail, and
re-compute its tail and

1079
00:58:54,270 --> 00:58:56,380
然后每次计算那个尾部 
recompute its tail each time,
you can see that's very

1080
00:58:56,380 --> 00:58:59,610
你可以看到那真是非常的不方便 
inefficient compared to just
having a list where the

1081
00:58:59,610 --> 00:59:02,510
并且 我得到下一个尾部 我不需要每次再次计算每个尾
elements are all there, and I
don't have to re-compute each

1082
00:59:02,510 --> 00:59:05,290
tail every time I get
the next tail.

1083
00:59:05,290 --> 00:59:15,030
所以这个小小的改变 改变了delay
So there's one little hack to
slightly change what delay is,

1084
00:59:15,030 --> 00:59:17,380
并且使这个事－－
and make it a thing which is--

1085
00:59:17,380 --> 00:59:20,390
我将会使用这种方法来写
I'll write it this way.

1086
00:59:20,390 --> 00:59:27,360
真实的实现 延时是一个对这个东西的缩略词
The actual implementation, delay
is an abbreviation for

1087
00:59:27,360 --> 00:59:31,000
memo-proc的过程
this thing, memo-proc
of a procedure.

1088
00:59:31,000 --> 00:59:35,150
memo-proc是一个特别的东西 这个东西转换了一个过程
Memo-proc is a special thing
that transforms a procedure.

1089
00:59:35,150 --> 00:59:39,250
拿一个没有参数的过程
What it does is it takes a
procedure of no arguments and

1090
00:59:39,250 --> 00:59:42,190
然后把它转换进一个过程
it transforms it into a
procedure that'll only have to

1091
00:59:42,190 --> 00:59:44,806
这个过程只需要做一次计算
do its computation once.

1092
00:59:44,806 --> 00:59:48,700
我的意思是  你给它一个过程
And what I mean by that is,
you give it a procedure.

1093
00:59:48,700 --> 00:59:51,950
memo-proc的结果 将会是一个新的过程
The result of memo-proc will be
a new procedure, which the

1094
00:59:51,950 --> 00:59:55,370
第一次调用这个过程后 将会运行院士的过程
first time you call it, will
run the original procedure,

1095
00:59:55,370 --> 01:00:00,040
记住得到的结果  
remember what result it got, and
then from ever on after,

1096
01:00:00,040 --> 01:00:01,610
当你调用它 这将不会做这个计算
when you call it, it just
won't have to do the

1097
01:00:01,610 --> 01:00:02,360
computation.

1098
01:00:02,360 --> 01:00:05,200
这将会在某个地点cached结果
It will have cached that
result someplace.

1099
01:00:05,200 --> 01:00:06,550
这个是memo-proc的实现
And here's an implementation
of memo-proc.

1100
01:00:06,550 --> 01:00:11,210

1101
01:00:11,210 --> 01:00:12,710
当你有了这个想法 实现就变得简单了
Once you have the idea, it's
easy to implement.

1102
01:00:12,710 --> 01:00:15,830
memo-proc就是这个有两个flags的小东西
Memo-proc is this little
thing that has two

1103
01:00:15,830 --> 01:00:17,390
little flags in there.

1104
01:00:17,390 --> 01:00:20,320
它说 我已经开始运行了吗
It says, have I already
been run?

1105
01:00:20,320 --> 01:00:23,620
一开始它说 不 我还没有开始运行
And initially it says, no, I
haven't already been run.

1106
01:00:23,620 --> 01:00:29,070
上次 我运行的结果是什么
And what was the result I got
the last time I was run?

1107
01:00:29,070 --> 01:00:32,200
所以 memo-proc用一个叫proc的过程
So memo-proc takes a procedure
called proc, and it returns a

1108
01:00:32,200 --> 01:00:34,360
这个过程返回了一个没有参数的新的过程
new procedure of no arguments.

1109
01:00:34,360 --> 01:00:38,610
prov被认为是一个没有参数的过程
Proc is supposed to be a
procedure of no arguments.

1110
01:00:38,610 --> 01:00:42,970
他说 如果我没有已经运行
And it says, oh, if I'm not
already run, then I'm going to

1111
01:00:42,970 --> 01:00:44,430
然后我将会做一个序列的事情
do a sequence of things.

1112
01:00:44,430 --> 01:00:48,450
我将会计算proc 我将会保存那个
I'm going to compute proc,
I'm going to save that.

1113
01:00:48,450 --> 01:00:51,140
我将会存储那个在变量的结果
I'm going to stash that in
the variable result.

1114
01:00:51,140 --> 01:00:53,510
我将会为我做一个笔记 来表示 我已经运行了
I'm going to make a note to
myself that I've already been

1115
01:00:53,510 --> 01:00:56,610
然后 我将会返回结果
run, and then I'll return
the result.

1116
01:00:56,610 --> 01:00:59,010
所以 那时如果你计算它  如果它没有运行
So that's if you compute it
if it's not already run.

1117
01:00:59,010 --> 01:01:01,040
如果你调用它 并且这个已经运行了
If you call it and it's already
been run, it just

1118
01:01:01,040 --> 01:01:03,420
这个只会返回结果
returns the result.

1119
01:01:03,420 --> 01:01:08,400
所以 这是一个有点聪明的hack叫memoization
So that's a little clever
hack called memoization.

1120
01:01:08,400 --> 01:01:12,100
在这个情况 
And in this case, it short
circuits having to re-compute

1121
01:01:12,100 --> 01:01:15,270
这短路不得不再次计算尾部的尾部的尾部等等等等
the tail of the tail of the tail
of the tail of the tail.

1122
01:01:15,270 --> 01:01:17,810
这里甚至不是那么无效率
So there isn't even that
kind of inefficiency.

1123
01:01:17,810 --> 01:01:20,590
事实上 流将会和上一个程序有一样的效率
And in fact, the streams will
run with pretty much the same

1124
01:01:20,590 --> 01:01:24,210
efficiency as the other
programs precisely.

1125
01:01:24,210 --> 01:01:28,110
记住 再说一下 这整个思想是
And remember, again, the whole
idea of this is that we've

1126
01:01:28,110 --> 01:01:32,390
我们使用了一个事实：过程和数据之间没有一个合适的分界线
used the fact that there's no
really good dividing line

1127
01:01:32,390 --> 01:01:33,610
between procedures and data.

1128
01:01:33,610 --> 01:01:36,510
我们写的数据结构在事实上 都在某些方面像过程
We've written data structures
that, in fact, are sort of

1129
01:01:36,510 --> 01:01:38,760
like procedures.

1130
01:01:38,760 --> 01:01:45,280
允许我们做的是 在这个iteration位置带一个普遍的控制结构的例子
And what that's allowed us to
do is take an example of a

1131
01:01:45,280 --> 01:01:49,620
common control structure,
in this place iteration.

1132
01:01:49,620 --> 01:01:52,460
并且 我们建造了一个数据结构
And we've built a data structure
which, since itself

1133
01:01:52,460 --> 01:01:54,530
因为它本身是一个过程
is a procedure, kind of has
this iteration control

1134
01:01:54,530 --> 01:01:55,496
里面有这个iteration控制结构
structure in it.

1135
01:01:55,496 --> 01:01:58,650
那个就是流了
And that's really what
streams are.

1136
01:01:58,650 --> 01:01:59,900
好的 有什么问题
OK, questions?

1137
01:01:59,900 --> 01:02:03,950

1138
01:02:03,950 --> 01:02:06,110
你的尾尾尾描述 
AUDIENCE: Your description
of tail-tail-tail, if I

1139
01:02:06,110 --> 01:02:10,050
如果我理解的是对的
understand it correctly, force
is actually execution of a

1140
01:02:10,050 --> 01:02:13,052
force只是一个过程的执行 如果它被完成没有使用这个memo-proc
procedure, if it's done without
this memo-proc thing.

1141
01:02:13,052 --> 01:02:16,380
并且 你暗示那个memo-proc 避免了这个问题
And you implied that memo-proc
gets around that problem.

1142
01:02:16,380 --> 01:02:20,580
这个
Doesn't it only get around it
if tail-tail-tail is always

1143
01:02:20,580 --> 01:02:22,550
如果 尾尾尾 总是完全一样的执行
executing exactly the same--

1144
01:02:22,550 --> 01:02:23,500
欧  那个是－－
PROFESSOR: Oh, that's--

1145
01:02:23,500 --> 01:02:23,910
是的
sure.

1146
01:02:23,910 --> 01:02:26,050
我估计 我漏掉了这点
AUDIENCE: I guess I
missed that point.

1147
01:02:26,050 --> 01:02:26,540
欧 是的
PROFESSOR: Oh, sure.

1148
01:02:26,540 --> 01:02:27,790
我的意思是
I mean the point is--

1149
01:02:27,790 --> 01:02:31,160

1150
01:02:31,160 --> 01:02:31,290
是的
yeah.

1151
01:02:31,290 --> 01:02:34,160
我的意思是 我不得不做这个计算来得到答案
I mean I have to do a
computation to get the answer.

1152
01:02:34,160 --> 01:02:37,590
但是这个点是  当我找到流的尾部
But the point is, once I've
found the tail of the stream,

1153
01:02:37,590 --> 01:02:39,530
来得到 尾的尾
to get the tail of the tail,
I shouldn't have had to

1154
01:02:39,530 --> 01:02:42,980
我不应该不得不再次计算第一个尾
re-compute the first tail.

1155
01:02:42,980 --> 01:02:45,370
看 如果我没有使用memo-proc
See, and if I didn't use
memo-proc, that re-computation

1156
01:02:45,370 --> 01:02:46,460
那个再次计算将会被做完
would have been done.

1157
01:02:46,460 --> 01:02:47,710
我理解了
AUDIENCE: I understand now.

1158
01:02:47,710 --> 01:02:50,830

1159
01:02:50,830 --> 01:02:52,550
在你的一个例子中
AUDIENCE: In one of your
examples, you mentioned that

1160
01:02:52,550 --> 01:02:55,010
你提到 我们可以使用替换模型
we were able to use the
substitution model because

1161
01:02:55,010 --> 01:02:56,830
因为这里没有副作用
there are no side effects.

1162
01:02:56,830 --> 01:03:01,040
如果 我们有一个单个处理单元
What if we had a single
processing unit--

1163
01:03:01,040 --> 01:03:03,620
如果 我们有一个副作用  如果我们有状态
if we had a side effect,
if we had a state?

1164
01:03:03,620 --> 01:03:09,120
我们可以建立流模型吗
Could we still practically
build the stream model?

1165
01:03:09,120 --> 01:03:09,530
可能吧
PROFESSOR: Maybe.

1166
01:03:09,530 --> 01:03:10,540
这是一个难题
That's a hard question.

1167
01:03:10,540 --> 01:03:15,540
我们等等再来谈这个替换和副作用没有完全结合好的地方
I'm going to talk a little bit
later about the places where

1168
01:03:15,540 --> 01:03:18,960
substitution and side effects
don't really mix very well.

1169
01:03:18,960 --> 01:03:21,170
但是一般的 我觉得这个答案 除非你非常小心
But in general, I think the
answer is unless you're very

1170
01:03:21,170 --> 01:03:23,920
任何数量的副作用将会把每个事情搞糟
careful, any amount of side
effect is going to mess up

1171
01:03:23,920 --> 01:03:25,170
everything.

1172
01:03:25,170 --> 01:03:35,490

1173
01:03:35,490 --> 01:03:36,150
学生：不好意思 我没有完全理解 memo-proc操作
AUDIENCE: Sorry, I didn't
quite understand

1174
01:03:36,150 --> 01:03:39,410
the memo-proc operation.

1175
01:03:39,410 --> 01:03:41,990
你什么时候执行lambda
When do you execute
the lambda?

1176
01:03:41,990 --> 01:03:46,270
换句话说 当memo-proc被执行
In other words, when memo-proc
is executed, just this lambda

1177
01:03:46,270 --> 01:03:47,600
expression is being generated.

1178
01:03:47,600 --> 01:03:50,390
但死 当这个被执行 这个对我不清楚
But it's not clear to me
when it's executed.

1179
01:03:50,390 --> 01:03:51,350
教授：好的
PROFESSOR: Right.

1180
01:03:51,350 --> 01:03:53,890
memo-proc做的是   记住
What memo-proc does-- remember,
the thing that's

1181
01:03:53,890 --> 01:03:57,290
进入memo-proc的东西
going into memo-proc, the thing
proc, is a procedure of

1182
01:03:57,290 --> 01:03:57,930
是proc  是一个没有参数的过程
no arguments.

1183
01:03:57,930 --> 01:04:00,390
某些时候 你将会调用它
And someday, you're
going to call it.

1184
01:04:00,390 --> 01:04:03,350
memo-proc转换那个过程到另一个没有参数 并且你以后会调用的过程
Memo-proc translates that
procedure into another

1185
01:04:03,350 --> 01:04:05,110
procedure of no arguments,
which someday

1186
01:04:05,110 --> 01:04:06,620

you're going to call.

1187
01:04:06,620 --> 01:04:09,890
那个是lambda
That's that lambda.

1188
01:04:09,890 --> 01:04:17,370
所以这里 当我一开始建立我流的尾部
So here, where I initially
built as my tail of the

1189
01:04:17,370 --> 01:04:20,680
我们以后会调用的没有参数的过程
stream, say, this procedure
of no arguments, which

1190
01:04:20,680 --> 01:04:24,100
someday I'll call.

1191
01:04:24,100 --> 01:04:27,130
反而 我将会有流的尾是它的memo-proc
Instead, I'm going to have
the tail of the stream be

1192
01:04:27,130 --> 01:04:30,650
这个东西将会在我们以后调用
memo-proc of it, which
someday I'll call.

1193
01:04:30,650 --> 01:04:35,340
nil的lambda被调用  当你调用memo-proc
So that lambda of nil, that gets
called when you call the

1194
01:04:35,340 --> 01:04:40,990
当你调用那个memo-proc的结果
memo-proc, when you call the
result of that memo-proc,

1195
01:04:40,990 --> 01:04:44,400
那个结果将会是一般地 当你想要调用你设置的原始的东西
which would be ordinarily when
you would have called the

1196
01:04:44,400 --> 01:04:47,642
original thing that
you set it.

1197
01:04:47,642 --> 01:04:49,690
好吧 我问这个的原因是
AUDIENCE: OK, the reason I ask
is I had a feeling that when

1198
01:04:49,690 --> 01:04:52,610
我有一种感觉 当你调用memo-proc  你只需要返回这个lambda
you call memo-proc, you just
return this lambda.

1199
01:04:52,610 --> 01:04:53,770
教授：对的
PROFESSOR: That's right.

1200
01:04:53,770 --> 01:04:58,100
当你调用memo-proc 你返回lambda
When you call memo-proc,
you return the lambda.

1201
01:04:58,100 --> 01:05:00,090
你从不计算表达式
You never evaluate the
expression at all, until the

1202
01:05:00,090 --> 01:05:02,270
直到你第一次计算它
first time that you would
have evaluated it.

1203
01:05:02,270 --> 01:05:07,590

1204
01:05:07,590 --> 01:05:10,000
学生： 不知道我理解的对不对
AUDIENCE: Do I understand it
right that you actually have

1205
01:05:10,000 --> 01:05:12,980
你实际建造了一个列表 但是列表中的元素没有被计算
to build the list up, but
the elements of the

1206
01:05:12,980 --> 01:05:14,240
list don't get evaluated?

1207
01:05:14,240 --> 01:05:15,630
表达式没有被计算？
The expressions don't
get evaluated?

1208
01:05:15,630 --> 01:05:18,540
但是在每个阶段  你实际上建立了一个列表
But at each stage, you actually
are building a list.

1209
01:05:18,540 --> 01:05:19,750
教授： 那个是
PROFESSOR: That's--

1210
01:05:19,750 --> 01:05:20,700
我真的应该说的
I really should have
said this.

1211
01:05:20,700 --> 01:05:22,270
这个真不错
That's a really good point.

1212
01:05:22,270 --> 01:05:23,660
不 这不是很正确的
No, it's not quite right.

1213
01:05:23,660 --> 01:05:25,080
因为就是这样发生的
Because what happens is this.

1214
01:05:25,080 --> 01:05:26,890
让我们把这个画成序对
Let me draw this as pairs.

1215
01:05:26,890 --> 01:05:29,710
假设 我将造一个大的流
Suppose I'm going to make a
big stream, like enumerate

1216
01:05:29,710 --> 01:05:32,740
像enumerate 间距1到1百万
interval, 1 through 1 billion.

1217
01:05:32,740 --> 01:05:43,045
那个是 一个1和一个许诺的序对
What that is, is a pair with
a 1 and a promise.

1218
01:05:43,045 --> 01:05:46,520

1219
01:05:46,520 --> 01:05:47,890
完全就是这样
That's exactly what it is.

1220
01:05:47,890 --> 01:05:49,140
什么都没有被建成
Nothing got built up.

1221
01:05:49,140 --> 01:05:51,600

1222
01:05:51,600 --> 01:05:56,370
当我force这个 然后说 会发生什么
When I go and force this,
and say, what happens?

1223
01:05:56,370 --> 01:06:00,530
好的 这个东西现在也递归一个cons
Well, this thing is now also
recursively a CONS.

1224
01:06:00,530 --> 01:06:07,770
所以 这个许诺诺现在是下一个东西 是2和一个许诺
So that this promise now is the
next thing, which is a 2

1225
01:06:07,770 --> 01:06:11,350
and a promise to do more.

1226
01:06:11,350 --> 01:06:14,470
等等等等
And so on and so on and so on.

1227
01:06:14,470 --> 01:06:18,200
所以 知道你走道流 没有东西被建造
So nothing gets built up until
you walk down the stream.

1228
01:06:18,200 --> 01:06:20,790
因为这里不是列表
Because what's sitting here is
not the list, but a promise to

1229
01:06:20,790 --> 01:06:24,250
而是一个产生列表的许诺
generate the list.
And by promise,

1230
01:06:24,250 --> 01:06:25,500
并且通过许诺  我的意思是过程 在技术上的
technically I mean procedure.

1231
01:06:25,500 --> 01:06:28,050

1232
01:06:28,050 --> 01:06:30,485
所以 这没有建成
So it doesn't get built up.

1233
01:06:30,485 --> 01:06:34,280
是的 我应该在这点之前说过了
Yeah, I should have said
that before this point.

1234
01:06:34,280 --> 01:06:34,490
好的
OK.

1235
01:06:34,490 --> 01:06:34,790
谢谢大家
Thank you.

1236
01:06:34,790 --> 01:06:36,340
下面进入休息时间
Let's take a break.

1237
01:06:36,340 --> 01:06:55,828
MIT OpenCourseWare
http://ocw.mit.edu


6.001 Structure and Interpretation of Computer Programs, Spring 2005





Please use the following citation format:

       Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and

       Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute
       of Technology: MIT OpenCourseWare).    http://ocw.mit.edu (accessed MM DD,
       YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike.


Note: Please use the actual date you accessed thismaterial in your citation.



For more information about citing these materials or our Terms of Use, visit:
http://ocw.mit.edu/terms
