CS61A Homework: Church Numerals
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
很厉害的题目。我是第一次以这种角度思考问题,这种体验令人很兴奋。
首先考虑补完 one
和 two
两个函数。
按照 zero
和 successor
的定义,我们很容易就能不动脑子地写出代码。当然,题目原本应该并非这个意思。
考虑稍微画两下,容易得到这样的代码:
def one(f):
return lambda x: f(x)
def two(f):
return lambda x: f(f(x))
由 successor
的定义,发现数字 \(N\) 对应的函数 \(F_N(f)\) 的定义应当为:
\]
也就是说,这里的数字 \(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\) 嵌套起来,即
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)
至此做完了。
其实写博客的时候就会发现许多事情想明白了却说不明白,这个或许还是要自己悟了。
CS61A Homework: Church Numerals的更多相关文章
- Church encoding
In mathematics, Church encoding is a means of representing data and operators in the lambda calculus ...
- 箭头函数 Arrow Functions/////////////////////zzz
箭头符号在JavaScript诞生时就已经存在,当初第一个JavaScript教程曾建议在HTML注释内包裹行内脚本,这样可以避免不支持JS的浏览器误将JS代码显示为文本.你会写这样的代码: < ...
- Swift 高阶函数
map.flatMap.filter和reduce,几乎实现lambda表达式的语言里都会在集合里增加这些方法, 见swift 学习(一)基础知识 (基本数据类型,操作符,流控制,集合)中的集合 ht ...
- 最新的JavaScript核心语言标准——ES6,彻底改变你编写JS代码的方式!【转载+整理】
原文地址 本文内容 ECMAScript 发生了什么变化? 新标准 版本号6 兑现承诺 迭代器和for-of循环 生成器 Generators 模板字符串 不定参数和默认参数 解构 Destructu ...
- 深入浅出ES6(七):箭头函数 Arrow Functions
作者 Jason Orendorff github主页 https://github.com/jorendorff 箭头符号在JavaScript诞生时就已经存在,当初第一个JavaScript教 ...
- 最新的JavaScript核心语言标准——ES6,彻底改变你编写JS代码的方式!
原文地址 迁移到:http://www.bdata-cap.com/newsinfo/1741515.html 本文内容 ECMAScript 发生了什么变化? 新标准 版本号6 兑现承诺 迭代器和f ...
- [CS61A] Lecture 5&6&7. Environments & Design & Functions Examples & Homework 2: Higher Order Functions
[CS61A] Lecture 5&6&7. Environments & Design & Functions Examples & Homework 2: ...
- [CS61A] Lecture 1&2&3. Introduction&Functions&Control
[CS61A] Lecture 1&2&3. Introduction&Functions&Control 前言 CS61A是加州大学伯克利分校一门计算机专业课程,用于 ...
- bzoj 4320: ShangHai2006 Homework
4320: ShangHai2006 Homework Time Limit: 10 Sec Memory Limit: 128 MB Description 1:在人物集合 S 中加入一个新的程序员 ...
随机推荐
- 关于h5游戏开发,你想了解的一切都在这儿!
2020年,受疫情影响,线下产业红利褪去,线上迎来的新一轮的高峰.众多商家纷纷抓住了转型时机,开启了流量争夺战.H5游戏定制无疑是今年引流的大热门.如何开发一款有趣.有爆点.用户爱买单的好游戏呢? ...
- 再深入一点|binlog和relay-log到底长啥样?
上一篇mysql面试的文章之后收到不少朋友的意见,希望深入讲讲复制.日志的格式这些,今天,我们就来深挖一下mysql的复制机制到底有哪一些,以及binlog和relay-log的结构到底是什么样子的. ...
- python应用 曲线拟合03
问题 有许多待拟合的曲线,需批量拟合. 解决 写一个类 # -*- coding: utf-8 -*- """ @author: kurrrr ""& ...
- Java实现简单混合计算器
这个计算器并不是基于逆波兰实现的,而是通过简单的递归,一层一层地计算最终求得结果. 具体的图形化界面可以参考我的另外一个篇博客:基于逆波兰表达式实现图形化混合计算器,这里我只是简单的介绍一下怎样求得算 ...
- nodejs解压版安装和配置(带有搭建前端项目脚手架)
nodejs 安装 我先前用了nvm,觉得nvm挺厉害可以随时更换nodejs版本,但是研究了下,可能自己功力不够还是什么,并不好用,中间还出现了错误:所以最后还是卸载了: 本文图文并茂的一步一步的 ...
- hystrix(3) 熔断器
讲完metrics我们就来了解一下熔断器的执行情况,熔断器的判断取决metrics数据. hystrix在执行命令前需要经过熔断器判断,如果服务被熔断,则执行fallback流程,熔断判断逻辑如下: ...
- .netcore 3.1 C# 微信小程序发送订阅消息
一.appsettings.json定义小程序配置信息 "WX": { "AppId": "wx88822730803edd44", &qu ...
- 理解 JAVABEAN EJB POJO
<Spring实战>第一章:基本理念.各类名称熟语 POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混 ...
- 后端开发实践:Spring Boot项目模板
在我的工作中,我从零开始搭建了不少软件项目,其中包含了基础代码框架和持续集成基础设施等,这些内容在敏捷开发中通常被称为"第0个迭代"要做的事情.但是,当项目运行了一段时间之后再来反 ...
- 对之前IoT项目的完善
博文有点长,因为是两个大项目(四个小项目)放一起了,不过都很适合新手小白(有源程序的情况),也可以再接 OLED 屏,就是前几篇博客的操作 一.esp8266 读取 DHT11 数据并通过微信小程序发 ...