一. Chruch Encoding为了解决什么问题??
lambda y.x*2
lambda 中的自然数 2 无法表示如何解决??
为此,就有了Church Encoding
二. Church Encodeing 简介
是 Church 发明的一种用 λ \lambda λ expression 表示自然数的方法.
通过函数的嵌套层数来表示!!!
三. 本质
f(x) 嵌套0次: x, 表示0
f(x) 嵌套1次: f(x), 表示1
f(x) 嵌套2次: f(f(x)), 表示2
...
f(x) 嵌套n次: f^n(x) 表示n
四. python 表示
为了便于理解,我们可以先用 Python 表示.
根据其本质,我们可以用函数表示chruch encoding.
def zero(x):
return x #嵌套层数为0表示0
def one(f,x):
return f(x) #嵌套层数为1,表示1
def two(f,x):
return f(f(x)) #嵌套层数为2,表示2
1.为什么必须有参数呢???
因为 λ \lambda λ expression 是匿名函数,如果没有参数(因变量),函数就没有意义(数学意义上).
2.zero 为什么要有两个参数???
对于 zero 而言其实只需要一个参数 x. 但为了接口标准化,还是加上f这个参数(这也是为了方便后续操作).
def zero(f, x): #即使不需要参数f,还是用出于接口通用化,将其引入.
return x #嵌套0层表示0
五. lambda expression 表示
我们都知道 lambda expression 是一个匿名函数.
在 lambda calculs 中, 的最基本的元素页必须是一个 lambda expression.
所以 x 要表示为 λ \lambda λx.x
-
0 表示为: λ \lambda λ x.x --接口标准化–> λ \lambda λ fx.x
-
1 表示为: λ \lambda λ fx.f(x)
-
2表示为: λ \lambda λfx.f(f(x))
-
3表示为: λ \lambda λfx.f(f(f(x)))
-
n表示为: λ \lambda λ fx.f^n(x)
注意,这里的()属于嵌套标识符,而不是应用标识符
5.1 successor
0 的后继为 1. n 的后继数为 n+1.
successor 的功能为: 给定一个 Chruch Number, 可以推出其后继数.
实现思路:
- 后继数比前一个数要多一层 f()的嵌套
- 如何实现??? 答: 给变量n外面包裹一层 f()即可.
令 successor = λ \lambda λnfx.f(n)
其中变量 n 为要进行操作的 chruch number.
zero = λfx.x
one = successor(zero) = λfx.f(zero) = λfx.f(λfx.x)
并不是我们所期待的 one = λfx.f(x)
- 怎么解决??? 对传进来的 lambda expression作 应用操作,消去其头部即可.
令 successor = λ \lambda λnfx.f(n (f)(x))
其中变量 n 为要进行操作的 chruch number(本身也属于λ表达式).
最内层的 (f)(x) 分别 n (λ表达式)的应用
zero = λx.x
one = successor(zero) = λfx.f(λfx.x (f)(x))
one = λnfx.f(x) # λfx.x(f)(x) 成功完成 β规约(替换) 更新为 x
所以我们得出:
successor = λnfx.f(n (f)(x))
其中n(f)(x) 中的
- n是一个lambda expression 也是一个 church number
- (f)(x) 是用来应用于n这个lambda表达式 完成 β 规约的
额外的验证
eg:
one = λfx.f(x)
succ = λnfx.f(n (f)(x))
two = succ(one)
=> λfx.f(one (f)(x))
=> λfx.f(λfx.f(x) (f)(x)) #n被替换为 λfx.f(x)
=> λnfx.f(f(x))
5.2 add_church(m, n):
对两个church number 做加法
m 和n的接口都为 (f, x), 只不过每个数嵌套的层数不同
m = λfx.f(f(f(x))) #3
n = λfx.f(f(x)) #2
那么加法实际上很好理解,将 m 中的 x 变量替换为 n 即实现层数相加(丘奇数的相加).
m+n = λfx.f(f(f( f(f(x)) ))) #5
以上操作等价为以下操作:
m+n
= m(f)(n(f)(x)) #将 m 函数的因变量 x, 替换为n函数.并去掉n函数的头部(对n进行$\beta$规约)
= f(f(f( n (f)(x) )))
= f(f(f( λfx.f(f(x)) (f)(x) )))
= f(f(f( f(f(x)) )))
此时可以看出结果为 5 层.
给其加上头部即可: λmnfx.f(f(f(f(f(x)))))
所以,加法expression为 : λfx.m(f)( n(f)(x) )
5.3 mul_church(m, n):
对两个church number 做乘法
λmnfx.m(n(f))(x)
m = λfx.f(f(x)) #2
n = λfx.f(f(f(x))) #3
两个 church number 相加,实际上是将 m 中的每一层 f 都扩充为 n层f.
m*n = λfx.f(f(f(f(f(f(x)))))) #2*3=6
如何实现呢???
- 首先毋庸置疑的是,m中的x变量不用改变.
m()(x) - 那对于 m 中的每个f, 都要对其进行替换(
β
\beta
β规约)
m(n)(x) - 但很明显,传进去的n是 λfx.xxx 这样形式的,我们不期望其 head 存在, 如何解决???
m = λfx.f(f(x)) #2
=> λfx.f(f(f(x))) ( λfx.f(f(f(x))) (x)) #2
- 我们已经很明显的发现了,当替换完m中的f变量后,原式m中的的 (x) 正好可以协助现在式子完成 β \beta β 规约,消去 λx
=> λfx.f(f(f(x))) ( λf.f(f(f(x))) ) #2
- 但 λf 无法消去,所以原式子跟改为
m(n(f))(x)
=> λx.f(f(f(x))) ( λx.f(f(f(x))) (x)) # (x) 协助完成规约
=> λx.f(f(f(x))) ( f(f(f(x))) ) # f(f(f(x))) 协助完成规约
=> f(f(f(f(f(f(x)))))) #替换完全完成
5.4 pow_church
这里还没有搞清楚,比较模糊与是如何替换的.
将 church_number 转换为 int 数字
> 即,如何统计 f(x) 嵌套的层数呢??
正常人类的思路都会从 0 开始计数,那么如何实现这一点呢??
four = λfx.f(f(f(f(x))))
如图所示,此 λ expression 有两个参数 f x. 其中,
- (x) 是函数 f 的应用.
- 函数 f 是递推公式.
如此一来,只需要将 x 作为初始值 0 .
f 设置为 λx.x+1
依靠 f 这个递推公式不断的递推即可.
λfλx.f(f(f(f(x)))) (λx.x+1)(0)
=> λf.f(f(f(f(0)))) (λx.x+1) #将全部x替换为了0,同时去掉了头部的 λx
=> λx.x+1(λx.x+1(λx.x+1( λx.x+1(0) ))) #将f全部替换为 λx.x+1,同时去掉了头部的 λf
=> λx.x+1(λx.x+1(λx.x+1( 1 ))) #β规约
=> λx.x+1(λx.x+1( 2 )) #β规约
=> λx.x+1(3) #β规约
=> 4 #β规约
给包裹一层函数外壳即:
λn.n(λx.x+1)(0)
或
lambda n: n(lambda x: x+1)(0)
或
def chruch_to_int(n):
return n(lambda x:x+1)(0)
可以将 chruch number 转换为 int.