Church Numerals

Nagging

南大的 SICP 实际上是 Berkeley CS61A 的 clone ,所以我有幸做到了这个 Homework02。

此外要感谢选课系统,让我一个工科学生也能有幸享受世界一流大学的 CS 课程。

今天是 SICP 的 Lecture 5 ,这些 higher-order function 的内容完全是我的知识盲区。可见我觉得自己稍微有点的那些水平充其量也就是百川灌河罢了。

南大给的讲义上说:

This section is out of scope for our course, so the problems below is optional.

That is, the problems in this section don't count for your final score and don't have any deadline.

Do it at any time if you want an extra challenge or some practice with high order function and abstraction!

既然都不计成绩,我觉得代码应该是能放到网上的。因此有了这篇文章。

P.s. 问过助教老师了,是可以发上网的

Homework

The logician Alonzo Church invented a system of representing non-negative integers entirely using

functions. The purpose was to show that functions are sufficient to describe all of number theory:

if we have functions, we do not need to assume that numbers exist, but instead we can invent

them.

Your goal in this problem is to rediscover this representation known as Church numerals. Here are

the definitions of zero , as well as a function that returns one more than its argument:

def zero(f):
return lambda x: x
def successor(n):
return lambda f: lambda x: f(n(f)(x))

First, define functions one and two such that they have the same behavior as successor(zero)

and successor(successor(zero)) respectively, but do not call successor in your

implementation.

Next, implement a function church_to_int that converts a church numeral argument to a

regular Python integer.

Finally, implement functions add_church , mul_church , and pow_church that perform addition,

multiplication, and exponentiation on church numerals.

##########################
# Just for fun Questions #
##########################
HW_SOURCE_FILE = 'lab02.py' from operator import add, mul, sub square = lambda x: x * x identity = lambda x: x triple = lambda x: 3 * x increment = lambda x: x + 1 def zero(f):
return lambda x: x def successor(n):
return lambda f: lambda x: f(n(f)(x)) def one(f):
"""Church numeral 1: same as successor(zero)"""
"*** YOUR CODE HERE ***" def two(f):
"""Church numeral 2: same as successor(successor(zero))"""
"*** YOUR CODE HERE ***" three = successor(two) def church_to_int(n):
"""Convert the Church numeral n to a Python integer. >>> church_to_int(zero)
0
>>> church_to_int(one)
1
>>> church_to_int(two)
2
>>> church_to_int(three)
3
"""
"*** YOUR CODE HERE ***" def add_church(m, n):
"""Return the Church numeral for m + n, for Church numerals m and n. >>> church_to_int(add_church(two, three))
5
"""
"*** YOUR CODE HERE ***" def mul_church(m, n):
"""Return the Church numeral for m * n, for Church numerals m and n. >>> four = successor(three)
>>> church_to_int(mul_church(two, three))
6
>>> church_to_int(mul_church(three, four))
12
"""
"*** YOUR CODE HERE ***" def pow_church(m, n):
"""Return the Church numeral m ** n, for Church numerals m and n. >>> church_to_int(pow_church(two, three))
8
>>> church_to_int(pow_church(three, two))
9
"""
"*** YOUR CODE HERE ***"

Solution

很厉害的题目。我是第一次以这种角度思考问题,这种体验令人很兴奋。

首先考虑补完 onetwo 两个函数。

按照 zerosuccessor 的定义,我们很容易就能不动脑子地写出代码。当然,题目原本应该并非这个意思。

考虑稍微画两下,容易得到这样的代码:

def one(f):
return lambda x: f(x) def two(f):
return lambda x: f(f(x))

successor 的定义,发现数字 \(N\) 对应的函数 \(F_N(f)\) 的定义应当为:

\[F_N(f) = f(F_{N-1}(f)) = \dots = \underbrace{f(f(f(\dots(f}_{N个}))))
\]

也就是说,这里的数字 \(N\) 实际上表示嵌套的 \(f\) 个数。很容易用归纳法证明。

接下来考虑 church_to_int 的实现。

容易发现 church_to_int 本质上就是计数嵌套的 \(f\) 有多少个。要数数,当然就是要逐层把函数嵌套走一遍了,每走一层就给计数变量加一。那么考虑将 \(f\) 设置为自增函数 increment 。这样,传入的参数值就是计数变量的初值,函数的返回值就是终值了。

def church_to_int(n):
return n(increment)(0)

然后是 add_church 。要实现这个函数当然可以一个循环跑下来。但是,那不够美。

这三个单行函数写下来,你还好意思用长篇大论去实现某个小功能吗?显然否。

考虑计算 \(m + n\) ,也就是把 \(m + n\) 个 \(f\) 套在一起。而我们知道 \(F_m\) 可以实现 \(m\) 次嵌套, \(F_n\) 可以实现 \(n\) 次嵌套,我们在 \(F_n\) 外面套一个 \(F_m\) 即可,那么就有:

def add_church(m, n):
return lambda f: lambda x: m(f)( n(f)(x) )

接下来考虑实现 mul_church ,计算 \(n \times m\) 也就是 \(m\) 个 \(n\) 相加,

换言之,要把 \(F_n\) 自己套自己套上 \(m\) 次,代码非常简单:

def mul_church(m, n):
return lambda f: m(n(f))

最后考虑 pow_church ,这其实是最富技巧性的一个,或许也是最简单的一个。

\(F_m(f)\) 的功用是将 \(m\) 个 \(f\) 嵌套起来,那么 \(F_n(F_m(f))\) 的功用也就是将 \(n\) 个 \(F_m\) 嵌套起来,即

\[\begin{align*}
F_n(F_m(f)) &= \underbrace{F_m(F_m(F_m(\dots(F_m}_{n个})))) \\
&= \overbrace{\underbrace{f(f(f(\dots(f(\underbrace{f(f(f(\dots(f(\dots \underbrace{f(f(f(\dots \dots \dots(f}_{m个})))))}_{m个})))))}_{m个}}^{n个}))))
\end{align*}
\]

这正是乘方的定义。

def pow_church(m, n):
return n(m)

至此做完了。

其实写博客的时候就会发现许多事情想明白了却说不明白,这个或许还是要自己悟了。

最新文章

  1. 【iOS】UITabView/UICollectionView 全选问题
  2. Consuming a RESTful Web Service
  3. Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
  4. 学习WPF——了解路由事件
  5. Scrum 项目2.0
  6. 修改eOS wingpanel的透明度与颜色
  7. Uva 225 Golygons
  8. 从输入url到页面返回到底发生了什么
  9. js检测数据类型四种办法
  10. Linux shell : 管道 |
  11. (1.16)mysql server优化之buffer pool
  12. 【设计模式】—— 观察者模式Observer
  13. Luogu P3957 跳房子
  14. 奇怪吸引子---Aizawa
  15. CentOS 7 64位更换内核安装锐速破解版
  16. NOSQL之MEMCACHE
  17. qt使用动态库(DLL)
  18. angular自定义指令命名的那个坑
  19. UVA-1601 The Morning after Halloween(BFS或双向BFS)
  20. <Android 应用 之路> 百度地图API使用(4)

热门文章

  1. css3渐变色实现小功能 ------ css(linaer-gradient)
  2. Sender(agumaster_crawler)->RabbitMq->Reciever(agumaster)
  3. Java实现文件夹下文件实时监控
  4. 三年前买的T440p目前淘宝二手价2300左右
  5. [LeetCode] 448. 找到所有数组中消失的数字(思维)
  6. 跟我一起学.NetCore之静态文件处理的那些事
  7. 云计算openstack共享组件——Memcache 缓存系统(4)
  8. 昨天还在for循环里写加号拼接字符串的那个同事,今天已经不在了
  9. ECMAScript 6新特性简介
  10. 关于取整函数ceil(),floor(),round()函数得应用