第一次读到这里的时候能从文字感觉到作者似乎想要展示什么很不得了的东西,但是那个时候还不能理解
这里内容所展示的意义,在学完编译原理再回头来看这个地方的内容确实挺震撼的
先来解释一下这段代码的意义:
(define (cons x y)
(lambda (op) (if (= 0 op) x y)))
(define (car a)
(a 0))
(define (cdr a)
(a 1))
上述方式中cons被实现为一个函数,它接受两个参数x 和 y,同时返回一个函数,该函数接收一个参数,以此判定返回x还是y.
在之前我们一直把cons当作像1,2,3…这样的基础数据类型来使用,但是当思考这个数据类型的特征时可以发现它其实就是代表一种选择
一个二选一的选择,作为上层的使用者,当创建一个cons的的时候就代表创建了一个待定的选择,这个选择会在以后某个时刻决定(使用car表示选择前者,使用cdr表示选择后者),所以完全可以把cons实现为一个函数,该函数可以保存传入的两个参数,并返回一个函数,该函数就是一个选择函数,如果没有car和cdr访问cons就可以用(a 0)和(a 1)的形式来选择元素(所以其实数组也可以这样抽象),car与cdr只是为了统一所定义的接口
从上面这个例子来看,一个抽象的数据类型(cons)完全可以由一组函数(通常分为selector与constructor)所定义,只要这些函数能达到符合的约定,比如这里的cons,只要能保证(car (cons a b))的结果为a,(cdr (cons a b))的结果为b即可,这一节的rational实现也是在说明这个抽象方法.这样做的一个好处就是上层使用者只用关心数据的使用接口,无需关心具体的接口实现,同时也给了下层实现的自由,只要能对上提供约定的接口.
现在来想一下数字的意义,假设只考虑整数和add运算,如果每个数字都是一个函数,假设1由函数one表示,2由于two表示…那么这些函数需要满足这样的约定:
(add (one) (one)) => (two)
(add (one) (two)) => (three)
;...
现在再来想一下数字这个类型它的意义,它的意义可以看作一个记录,一个重复的记录,它要保证对同一操作重复two次的结果和重复2次one的结果是一样的,这可以用可重入函数来表达(只要初始数据和执行次数一定,输出结果就一定)
(define zero (lambda (f) (lambda (x) x)))
;zero表示不重复f操作
(define one (lambda (f) (lambda (x) (f x))))
;one表示重复一次f操作
(define two (lambda (f) (lambda (x) (f (f x)))))
;two表示重复两次f操作
(define (add a b)
(lambda (f) (lambda (x) ((a f) ((b f) x)))))
;这里定义一个简单的可重入函数f
(define (f x) (+ x 1)
;测试
(((add one one) f) 0) => 2
((two f) 0) => 2
;即(add one one) == (tow)
到这里连最基础的数字也已经被函数所定义完成(虽然还很不完善)但是已经足够可以看出数据和函数几乎没有区别,数据即函数,这种抽象让我们去思考很多习以为常的基础数据所代表的意义,这确实是令人震撼的
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2128099421@qq.com