SICP 习题 2.6 讲的是丘奇计数,是习题2.4 和 2.5的延续。
这里大师们想提醒我们思考的是“数”究竟是什么,在计算机系统里能够怎样实现“数”。准备好開始脑洞大开吧:
题目先讲到以下的定义,首先是0的定义:
(define zero (lambda (f) (lambda (x) x)))
然后是操作+ 1的定义:
(define (add-1 n)
(lambda (f) (lambda (x) (f ((n f) x)))))
接着题目就要求我们依据以上的过程開始定义数 1 和 2, 然后再定义主要的+操作。
说实话,第一次看到这道题的时候我对着上面三行代码看了半天也是稀里糊涂的。搞不清楚这种代码和数字有什么关系。
当中一个关键是我总是希望zero能够被输出为0。而(add-1 zero)过程会输出一个数字1。
有谁说过仅仅有符号0才代表数字“零”呢?一个空空的口袋不能代表“零”吗? 又有谁说过仅仅有符号1才代表数字“壹”呢?在苍茫大地上孤独行走的我不能代表“壹”吗?
把你的脑洞开到这个程度差点儿相同你就能够理解丘奇计数了。
丘奇计数的基本想法就是通过调用0次函数来表示0,通过调用1次函数来表示1,以此类推。。
。
所以。这里的zero事实上是一个lambda过程,该过程接受还有一个过程作为參数,只是对该过程调用0次,什么叫调用0次呢,就是传人什么參数就返回什么參数喽。
相应的,(add-1 n)过程也是返回一个lambda过程。该过程接受还有一个过程作为參数,对该过程调用n+1次。
这样理解的话,1和2就easy定义了,就是定义和zero相似的lambda过程,只是这次各自是调用1次和2次传入的过程。代码例如以下:
(define one
(lambda (f) (lambda (x) (f x)))) (define two
(lambda (f) (lambda (x) (f (f x)))))
借着是要考虑怎样实现+的操作,我们知道丘奇计数里的“数”事实上就是调用传入过程的次数。那就比較简单,假设要将两个丘奇计数中的数n和m加起来。事实上就是对传入过程调用(n+m)次。用以下这种简单嵌套就能够实现了:
(define (plus first second)
(lambda (f)
(lambda (x)
((first f) ((second f) x)))))
最后你可能会有疑问,像这种计数有什么意义吗?
事实上这里体现的是更高阶的“数”的理解,我们能够通过简单的办法降阶。我们能够定义以下这样一个接近于无聊的过程:
(define (f x)
(display "*")
)
这个过程仅仅接受一个參数,过程体什么都不做,仅仅是打印一个*号。
由于丘奇计数事实上计算的是过程的调用次数,所以假设我们将以上过程使用在丘奇计数中,就能够通过打印出来的*号直观地感受到丘奇计数中“数”的概念。
比方运行((two f) ‘a)会打印2个*号。
运行((one f) ‘a)会打印1个*号。
很多其它调用例子请參考以下代码:
(define (start-test-2-6) (display "going to display 1:")(newline)
((one f) 'a)(newline)
(display "going to display 2:")(newline)
((two f) 'a) (newline)
(display "going to display 1+2:")(newline)
(((plus one two) f) 'a)
(newline)
(display "going to display 1+2+2")(newline)
(((plus (plus one two) two) f) 'a)
(newline) (display "end.") (newline))