分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(2)
来源:互联网 发布:2017商务笔记本 知乎 编辑:程序博客网 时间:2024/05/18 01:33
这里,我给出个人对于上一篇文章中题目的一种解答。
首先,对于 one
two
这两个函数的定义,这个对于很多人来说,应该是没有什么难度的。根据successor
的定义,我们可以得到下面两个函数的定义
def zero(f): return lambda x: xdef successor(n): return lambda f: lambda x: f(n(f)(x))def one(f): """Church numeral 1: same as successor(zero)""" "*** YOUR CODE HERE ***" return lambda x: f(zero(f)(x))def two(f): """Church numeral 2: same as successor(successor(zero))""" "*** YOUR CODE HERE ***" return lambda x: f(one(f)(x))three = successor(two)
好了,接下来是真正的实验——church_to_int(n)
函数。这里,有两种可能: 从 0 到 n 和 从 n 到 0。两种方法我都试过,不过从 0 到n 貌似出不来结果,如果你的解答是从 0 到 n 算出来的,麻烦告诉我一声。
那么,接下来让我们从two
到zero
进行分析(当然,你可以选择直接分析successor
,如果你没被他的定义搞晕的话)。
首先我们应该明白,two(f)
返回的是一个函数,该函数有一个formal parameter x
。然后,让我们更进一步,假定有这么一个变量x
存在,然后two(f)(x) == Two
。同样的,one(f)(x) == One, zero(f)(x) == Zero
(注意我这里用了大写)。
那么将有
two(f)(x) -> f(One)one(f)(x) -> f(Zero)
到了这里,是不是觉得,好像发现了什么呢?至少,很有规律,不是吗?
对于每一个 Church number function,我们都将比他小1
的函数的返回值,作为实参,再调用了一次f
函数。也就是说,对于一个数值为n
的函数,f
会被调用n
次(一般情况下是如此,后面我们将挑战这一权威)。说到这里,答案其实已经浮出了水面,如果你没有忘记题目额外给出的一个increment
函数的话。
def increment(x): return x + 1def 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 ***" return n(increment)(0)
是不是很惊讶,答案居然是如此的简洁(老实说,个人写出这个一行代码时,也是觉得挺震撼的,题目的设计者真是个天才)。每次调用increment
的时候,都会 +1
,我们执行了increment
n
次,也就得到了我们想要的int
值。
对于add_church
函数,直觉上,想要从 m
和n
而得到m+n
,我们只需要简单地从n
使用successor
递增m
步即可(当然,你也可以先判断哪一个比较小,这里暂时忽略这个问题)。于是,便有了下面这个解答:
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 >>> church_to_int(add_church(zero, three)) 3 """ "*** YOUR CODE HERE ***" num_m = church_to_int(m) while num_m > 0: n = successor(n) num_m -= 1 return n # there is a better solution below
不知道你对这个答案满意度如何,我呢,总觉得有些别扭。这里我们居然用了5 行代码!5这个数字也许不是很大,但比起上一个问题中的1行代码,确实有点太多了。不过,这里我先放一放,后面我们再来讨论这个问题。
好啦,先放下add_church
这么一个疙瘩,我们来看看mul_church
。
在告诉你答案前,我觉得,还是先来复习一下小学乘法:
2×3 表示 2 个 3 或 3 个 2
不管怎么样,还是先急着这个吧。
在前面我们实现church_to_int(f)
时,我们在每次调用f
时执行了+1
操作,最后得到了church 函数对应的 整数值。这里,我们可以如法炮制。不管,现在每次增加的是 m
而不是1
(这里判断m, n
那个比较小没有任何意义)。沿着这个思路,我们可能会写出:
def mul_church(m, n): num_m = church_to_int(m) add_m = lambda x: x + num_m return n(add_m)(0)
很遗憾,这个是错的。我们需要的是一个 church 函数,而不是一个数字。不过,这是一个很好的开端。我们需要返回一个高阶函数,该函数接收一个函数作为实参且church_to_int
利用该传入的实参计算对应的整数值。
接下来需要一个小小的跳跃。以我们church_to_int
的实现来看,难道你传一个increment
给我,我就得乖乖用他来一步一步加1
吗?!为什么我们不能自作主张,一步加m
呢?!(还记得上面说过的吗?
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 >>> church_to_int(successor(mul_church(three, four))) 13 """ "*** YOUR CODE HERE ***" num_m = church_to_int(m) add_m = lambda x: x + num_m return lambda f: n(add_m) # or just # return lambda f: n(lambda x: x + num_m)
现在,让我们回到前面的 add_church(m, n)
。上面给出的答案是,从 n
开始,一步一步,得到了 m + n
。但是,不管怎么说,这种做法总是不够优雅。得益于上面对mul_church(m, n)
的思考,有这么一个想法,我们能够一步就将m
加到n
呢?答案是,可以。
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 >>> church_to_int(add_church(zero, three)) 3 """ "*** YOUR CODE HERE ***" num_m = church_to_int(m) return lambda f: lambda x: num_m + n(f)(x)
虽然较之前面的答案更为的复杂,但个人觉得,也还算优雅。这里需要注意的一点是,lambda f: lambda x: n(f)(x)
就等价于 n
。当我们计算其对应的整数值时,加上了额外的 num_m
,于是也就得到了 m+n
对应的整数值。
是不是觉得很兴奋?非常的有趣,不是吗?到了这里,综合我的解说和你的理解,我相信,你有能力做出最后的 pow_church(m, n)
。来吧,尝试一下,不然我可就只能独享这大餐了。
- 分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(2)
- 分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(1)
- 分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(3)
- 一道关于SVM的机器学习作业题
- 一道Java的课后作业题
- 最近做的一道c++作业题
- 分享一道关于素数的笔试题
- 写一下我的第二篇博客吧,关于栈的,灵感来自一道作业题
- python一道关于随机数的练习题
- python一道关于标识符检查的题
- python一道关于堆栈的题
- python一道关于字典的题
- python一道关于编写计算器的题
- python一道关于文件操作的题
- python一道关于异常处理的问题
- python一道关于map()的题
- 关于函数声明表达式的一道题目
- 关于linux fork()函数的一道题
- 第十六周项目7 归并排序
- 最接近零的子数组和_LintCode
- 【Android入门】界面布局中的错误
- javaweb页面嵌入天气显示
- mapreduce入门 note2 【mapreduce标准流程|】
- 分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(2)
- IOS 之使用FMDB进行SQLite数据库操作——表的创建与修改,以及数据的增删改查和多线程操作数据库
- 十六周 项目1 堆排序
- 第十六周 项目1 验证算法 归并排序
- java十分钟速懂知识点——System类
- 第十六周--英文单词的基数排序
- 第16周—项目1(7)基数排序
- 第七周 项目四 队列数组
- 逻辑卷的管理