scheme中用lambda实现primitive

2013-05-15

以前看scheme时,记得scheme是说只有几个基本的core syntax。而primitive并没有算做这门语言的必须部分。当时觉得不可思议,这门语言怎么能离得开cons,car,cdr这些基本的primitive。不过当时也没有深究。

再回头看SICP时,有点震惊了。原来之后以说这些primitive并不算是语言必须的部分,是因为即使是一些primitive,用lambda,if,begin,define,quote等一些基本的元素也是可以定义出来的。scheme直接对计算本质的抽象是不需要机器的。

先看看如何用最基本的元素定义出cons,car,cdr:

(define (cons x y) (lambda (n) (if (= n 0) x y))) (define (car z) (z 0)) (define (cdr z) (z 1))

或者这样子:

(define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) p))) (define (cdr z) (z (lambda (p q) q)))

太强大了,只使用基本的core syntax就把cons这种primitive定义出来的。这个其实是做了一个闭包,将cons的参数值保存在了闭包中,然后car和cdr将保存的值从闭包中取出来。其实还有好多种办法定义出cons,比如下面利用的是从数字2a * 3b中可以解析得到a和b。

(define (cons a b) (* (expt 2 a) (expt 3 b))) (define (car z) (if (= 0 (remainder z 2)) (+ 1 (car (/ z 2))) 0)) (define (cdr z) (if (= 0 (remainder z 3)) (+ 1 (cdr (/ z 3))) 0))

类似地,像数字0,加法,也可以用基本的core syntax定义出来。比如,我们假设0就是0个#t的list,1是1个#t的list,n是n个#t的list,则:

(define zero '()) (define (zero? v) (null? v)) (define (add1 v) (cons #t v)) (define (sub1 v) (cdr v)) (define (+ x y) (cond ((zero? x) y) ((zero? y) x) (else (+ (add1 x) (sub1 y)))))

有了加法之后,定义乘法也就不是什么难事。

(define (* a b) (if (= b 1) a (+ a (* a (- b 1)))))

太神奇了,lambda真的是对计算本质的抽象,完全不信赖机器。

再回头来想,if为什么必须定义为core syntax而不是能procedure/primitive。因为求值顺序,用produce定义if会产生副作用。如果是用primitive定义的if,那么 (if test true false)中不管test是真还是假,true和false子句都是被执行的。

schemeprimitive

HNS.to is a highly insecure way of browsing Handshake domains and should only be used for demo or educational purposes. Click to see preferable resolutions methods