丘奇数(Church numeral)

看SICP练习2.6,令人郁闷(中英文都是)。这个练习题告诉我们, 通过丘奇的lambda演算,我们可以定义最原始的数据和操作。这是编程语言设计者使用的武器。

对于应用程序员,需要知道的是:函数编程语言把函数视为数据

换言之,编程语言中的一切元素,归根结底都是λ表达式;正如命令思维的人认为的:编程语言中的一切元素,归根结底都是0和1.

但是对于程序员(语言使用者),我们了解了“归根结底”之后,真正需要知道的是:函数是数据。(而不是相反,数据也是λ表达式)。


“数据意味着什么?”我不知道作者为什么这样写。我认为,如果是寻根之旅,就应该明确说明:本节的中心思想是“归根结底”。

通常,我会将这一部分的内容放在最开始的引言中介绍。参考《编程导论(Java)·1.4.3函数式编程范式》

yqj2065个人认为,练习2.6是SICP整本书中最重要的一个练习题。

1.丘奇数的含义

丘奇数(Church numeral),并不是一个数字,而是指应用某个函数的次数。高阶函数Church- zero有两个参数f和x,表示丘奇数0,即函数f应用0次。同理可得丘奇数1和丘奇数2。

(define Church-zero (lambda (f) (lambda (x) x)))

(define Church-one
  (lambda (f)
    (lambda (x)
      (f x))))    ;;;应用1次f

(define Church-two
  (lambda (f)
    (lambda (x)
      (f (f x))))) ;;;应用2次f

假设有求平方的函数square(这里假设——当然Scheme也已经定义了乘法操作符*)。

(define (squarex) (* x x))

应用函数Church-two,其参数为square和3(这里假设已经定义了数字3)

((Church-two square) 3) →81

当对参数3应用两次求平方函数square,结果为81。

【附:练习2.6中要求通过代换求(add-1 zero)的值的方式,给出丘奇数1和丘奇数2(不得直接使用add-1和 zero)。已知add-1

(define (add-1 n)
  (lambda (f) (lambda (x) (f ((n f) x)))))

先看看代换规律:例如

(define add (lambda (x y) (+ x y)))
(add 1 2 )→(+ 1 2) ;;;β简化

所以(注lambda (f)写成λf,使用α-变换和β简化)

Church-one = (++ Church-zero)

=>  (λn.λf.λx.(f ((n f) x)) Church-zero)

=> λf.λx.(f ((Church-zero f) x));;; β简化。

=> λf.λx.(f ((λg.λy.y f) x));;α-变换,避免混淆

=>λf.λx.(f (λy.y x)) ;;; β简化

=>λf.λx.(f x) ;;; β简化

最后得:

(define one (lambda (f) (lambda (x) (f x))))  】


2. 定义数字my0、my1、my2

为了定义数字zero、one、two……,首先需要定义一个自增函数++(SICP上的add-1),其参数有3个。其中n是一个丘奇数。

(define (++ n)

  (lambda (f)(lambda (x) (f ((n f) x)))))

从Church-zero和++,可以简单地定义Church-one:

(define Church-one (++ Church-zero))

也可以通过代换的方式求(++zero)的值,给出丘奇数1和丘奇数2的直接定义。

但是,单纯地通过丘奇的λ演算——即不使用任何Scheme已经定义的东西,定义数字zero难度太大。所以,借用Scheme已经定义的数字1和+,自增函数++为:

(define ++ (lambda (x) (+ x 1)))

在这个投机取巧的自增函数++基础上(借用Scheme已经定义的数字0),我们得到数字my0、my1、my2的定义:

(define my0 ((Church-zero ++) 0))

(* 2 my0)

(define my1 ((Church-one ++) 0))

(* 2 my1)

(define my2 ((Church-two ++) 0))

3.直接定义+

根据++函数,丘奇数m+n的+函数定义为:

+ =  λm.λn.λf.λx.((((m ++) n) f) x)

验证如下:求丘奇数2+1

((+ Church-two) Church-one) = ((λm.λn.λf.λx.((((m++) n) f) x) Church-two) Church-one)

=> (λn.λf.λx.(((( Church-two ++)n) f) x)Church-one);;; β简化,替换m

=>λf.λx.(((( Church-two ++)  Church-one)  f)  x) ;;; β简化,替换n

=>λf.λx.(( ( ( λg.λy.(g (g y)) ++)  Church-one)  f)  x) ;; 展开与α-变换

=>λf.λx.((( λy.(++ (++ y)) Church-one)  f)  x)

=>λf.λx.((      (++ (++ Church-one) )  f)  x) ;; 已知(++ Church-one)= Church-two

=>λf.λx.((  ( ++ Church-two )  f)  x)  ;; 展开++

=>λf.λx.((  ( λn.λg.λy.(g ((n g) y)) Church-two ) f)  x)

=>λf.λx.(( λg.λy. (g ((Church-two g) y))  f)  x)

=> λf.λx.((  λg.λy.(g ( (λh.λz.(h (h z))  g) y))  f)  x)

=>λf.λx.((   λg.λy.(g  (λz.(g(g z))  y)    )  f)  x)

=>λf.λx.(  (λg.λy.(g (g (g y)))  f)  x)

=>λf.λx.( λy.(f (f (f y)))  x)

=>λf.λx.(f (f (f x)))

 

参考:
Church Numerals

你可能感兴趣的:(丘奇数(Church numeral))