#111723#<h2 style="text-indent: 2em;">王垠王垠[yín],四川大学97级本科结业,输送到清华大学盘算机系直博。时期曾在清华大学盘算机系软件工程专业就读,重要停止集成电路布线算法的研讨。在此时期,他因《完整用GNU/Linux任务》一文和对TeX的推行等“非研讨结果的专业货色”而闻名。 在只剩一年就要博士结业的时间,他请求退学,并将1万7千余字的“退学请求书”(题为清华梦的破碎)颁布在网上,引发言论界一时对教导体系、幻想主义等的热议。
<h2 style="text-indent: 2em;">王垠的40行代码 40行代码专家解读<h4 style="text-indent: 2em;">1. 配景常识CPS: Continuation-Passing Style. 有一篇先容 CPS 艰深易懂的文章(中文翻译)。
简略来说,CPS 是一种编程作风:
Javascript:
(原味)
function foo(x) {
return x ;
}
(CPS)
function cps_foo(x, return_point) {
return return_point (x) ;
}
CPS 多了一个参数 return_point,return_point 来自 caller ,是 caller 地点的“天下”,caller 将这个“天下” 通报给 callee (cps_foo),如许 cps_foo 就不必应用额定的东西(比方客栈)去查问 caller 的天下在那里,以便前往,而是直接进入这个天下:return_point (x)。 这就是 CPS 的初志 —— 去掉层层嵌套的天下。行话讲就是 desugar(脱糖)。Syntax sugar 是为了便利人类的表白和懂得,给编程言语的中心套上的一层好吃难看的外套,而对呆板对顺序的说明,须要将其复原到最实质的构造,以便机器化处置和优化,这 就是脱糖的意思。
以函数式编程的观念来看,return_point 是一个函数,以 C 观念来看,你能够把它懂得为顺序地点,或许,以 Matrix 来看,它是 key-maker 翻开门进入新天下的那把钥匙。“天下”上只有一个宏大的顺序(比方,你的顺序不外是在 chrome 外面运转的一个小顺序,而 chrome 又是在 OS 外面的一个小顺序),return_point 将种种小顺序窜连起来了。恩,差未几就是这个意思。只不外,在函数式顺序外面(比方Scheme)外面,return_point 是函数,而在进程式顺序(比方C)外面它更像是 0x4f36a0c4。
这段 40 多行代码是给 Scheme 顺序脱糖的顺序,属于说明器的代码,而不是利用代码。对其的客观评估明显只有计划说明器的人材能给出。对利用顺序员的意思在于,发明天天下班时编写的代码如许无聊,另外并没有任何适用代价。
<h4 style="text-indent: 2em;">2. 运转成果‘x
’(lambda (x k) (k x))
‘(lambda (x k) (x 1 k))
’(f x (lambda (v0) (if v0 a b)))
‘(if x (f a (lambda (v0) v0)) b)
’(lambda (x k) (f x (lambda (v0) (if v0 (k a) (k b)))))
‘(lambda (x k) (let ((k (lambda (v0) (if v0 (k c) (k d))))) (if x (f a k) (k b))))
’(lambda (x k) (let ((k (lambda (v0) (if v0 (k c) (k d))))) (if x (k (zero? a)) (k b))))
‘(lambda (x k) (if t (if x (f a k) (k b)) (k c)))
’(lambda (x k) (let ((k (lambda (v0) (if v0 (k e) (k w))))) (if t (if x (f a k) (k b)) (k c))))
‘(lambda (x k) (let ((k (lambda (v0) (h v0 k)))) (if x (f a k) (k b))))
’(lambda (x k) (let ((k (lambda (v0) (v0 c k)))) (if x (f g k) (k h))))
‘(f a (lambda (v0) (g b (lambda (v1) (v0 v1 (lambda (v2) (f c (lambda (v3) (g d (lambda (v4) (v3 v4 (lambda (v5) (v2 v5 (lambda (v6) v6))))))))))))))
’(lambda (n k)
((lambda (fact k) (fact fact (lambda (v0) (v0 n k))))
(lambda (fact k)
(k
(lambda (n k)
(if (zero? n)
(k 1)
(fact
fact
(lambda (v1) (v1 (sub1 n) (lambda (v2) (k (* n v2))))))))))
k))
120
原代码中最后一句 ((eval fact-cps ) 5 (lambda (v) v)) 在 racket 中要修正为:
((eval fact-cps (make-base-namespace)) 5 (lambda (v) v)) 才干通过算得 120。
<h4 style="text-indent: 2em;">3. 解释<h4 style="text-indent: 2em;">4. 要点ctx: 函数在履行(apply)时间的高低文情况,可懂得为 C 顺序中运转时的栈。
整 个 cps 的(重要)进程就是 if 分支在一直制作新的 ctx, 而 apply 分支(最后一个分支)一直在新的 ctx 中 ‘盘算’ (现实上是天生 cps 函数的代码,而不是真的盘算),并前往成果(到上一层 ctx)的进程。这个进程就是 scheme 的基础 eval-apply 进程。(拜见SICP第四章)
这是一个说明器(说明成为 CPS 作风的代码),同时也是一个CPS转换器,正所谓 Compiling with Continuations. 别的,Scheme 这类代码即数据(字符串列表)的特征,使得编写天生代码的代码绝对轻易和简练。
至于代码为何有 k 这个定名。呵呵,你能够叫它 kontinuation 或许 klosure.
<h4 style="text-indent: 2em;">5. 论断以天然言语写作比方,编写自说明器级其余代码,就像你在写一本小说,而小说的配角也在写一本小说,这位配角在描述你,对你的描绘会影响到你,你遭到影响以后又会转变小说中的配角,从而影响到他对你的描述。你俩要相安无事,情节合符逻辑地开展,直到最后美满的开头。这比写一本一般小说可难多了。
<h3 style="text-indent: 2em;">网友评估:看来网友们存眷的重点,都在王垠说的话上,良多网友都以为他在吹嘘。然而也有网友为他谈话的,感到这40行代码,确切很利害,有些网友还静静的跑去运转了一下。
网友一:这40行代码的代价,开端我是不认为然的。由于基本不懂它是干吗用。直到本人程度的晋升,又对这些代码有研讨,才发明,这40行代码的代价。
网友二:这40行代码的代价既然不在于实现了CPS的算法,也不在于这段代码写得有如许精简和奇妙。而是:自力思考。
网友三:这段代码的功效是主动把一般递归转换为尾递归。
网友四:不懂js的人,就算是简略的js代码也看不懂的。 良多人看不懂不代表没有人看得懂。
更多内容阅读推荐:
电磁炉不检锅什么原因