2019-06-30
Scheme
Church Encoding
Church Encoding 是一种以函数的调用次数为计数方式的编码方式[1]编码是这样的一套规则,它定义了从符号集到某事物的映射关系,比方以数字 2 代表第二个东西。 ,比如将调用 0 次定义为 0,把增加一次调用定义为自加:
  1. 将 0 定义为:f -> x -> x
  2. 将 1 定义为:f -> x -> f(x)
  3. 将 2 定义为:f -> x -> f(f(x))
  4. 依此类推

# Church Encoding

按照 Church Encoding 的定义,我们可以很容易的写出 Church Encoding 中的 0 1 2
00;; 定义 0 
01(define zero
02    (lambda (f) (lambda (x) x)) )
03
04;; 直接写出 1 的定义
05(define one
06    (lambda (f) (lambda (x) (f x))))
07
08;; 直接写出 2 的定义
09(define two
10    (lambda (f) (lambda (x) (f (f x) ))))
Church 其实是一种计数方式,因此需要定义它如何计数,而它是利用函数的调用次数来计数的,因此,它的自增可以这样实现:
00;; 定义自加
01(define (add-1 n)
02    (lambda (f)
03        (lambda (x)
04            (f ((n f) x)))))
那,两个 Church Number 之间的加法怎么弄呢?比如 a + b,那么需要把 f 调用 (a + b) 次就行,实现如下:
00;; 写出 Church Encoding 的加法
01(define (add a b)
02    (lambda (f)
03        (lambda (x)
04            ((a f) ((b f) x)) )))

# 退化为正整数

注意到这种编码方式是以函数的调用次数为计数方式,因此我们可以将这种编码方式用来编码我们的正整数,也就是将 Church Encoding 退化为我们熟知的整数:
00;; 利用 inc 将 Church 退化为数学上的正整数
01
02;; 这个是数学上的自加
03(define (inc x) (+ x 1))
04
05;; one 是上面的定义,这里的结果是整数 1
06((one inc) 0)
07;; 结果是整数 2
08((two inc) 0)
09
10;; 验证 add 是否正确 (如果正确,则结果应该是 3)
11(define three (add one two))
12((three inc) 0)
有趣。

# JavaScript 等价写法

00// 定义 0 
01const zero = f => x => x;
02
03// 直接写出 1, 2 的定义
04const one = f => x => f(x);
05const two = f => x => f(f(x));
06
07// 定义自加
08const add_1 = n => f => x => f(n(f)(x));
09
10// 写出 Church Encoding 的加法
11const add = (a, b) => f => x => a(f)(b(f)(x));
12
13// 整数自加
14const inc = x => x + 1;
15
16// 测试
17console.log('Church To Number 1:', one(inc)(0));
18console.log('Church To Number 2:', two(inc)(0));
19
20const three = add(one, two);
21console.log('Church To Number 3:', three(inc)(0));
虽然 js 写起来简洁很多,但是括号和表达式的中缀写法使得函数体读起来不太舒服(很多括号)

  1. 编码是这样的一套规则,它定义了从符号集到某事物的映射关系,比方以数字 2 代表第二个东西。 ↩︎




回到顶部