分享一道伯克利 CS 61A 关于高阶函数的一道Python作业题(3)

废话不多说,我们来看看pow_church(m, n)该如何实现。

这里我们需要计算 mn 。这一次,我们采取另一种办法 —— 先给出解答。

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
    >>> four = successor(three)
    >>> five = successor(four)
    >>> church_to_int(pow_church(five, three))
    125
    """
    "*** YOUR CODE HERE ***"
    return n(m)

我想,看到这个答案的时候,你一定和我一样的惊奇。不过,这一个答案其实我是做实现mul_church()的时候发现的。当时的想法是,既然 church 函数是对实参f应用(apply / call)n次,那么,n(m)不就应该是 n * m了吗?然后结果出乎了我的意料,他是m ** n


我们先看看调用pow_church(two, three)时,究竟施展了什么样的魔法,能够使得结果是m ** n


调用pow_church(two, three),我们可以得到

eight = lambda f: two(two(two)(f))

这里就让人有些困惑了,我自己都搞晕了呢。仔细看看中间的实参,有个two(two)。说来有些可笑,闹了这么久,我们貌似没有前进多少。不过,我可不会轻易放弃。


在继续前进之前,让我们往回走几步,再再谈一谈 church 函数到底做了什么事。对于 church_n(f)(x),实际将执行f(f(f( .. f(x) .. ))),一共 nf 。只有理解了这一点,我们才能够明白上面的表达式究竟代表会有什么样令人惊奇的行为。

下面我们先以four = two(two)为例,按照上面所述的规则,看看他会变成什么模样:

four(f)(x)

two(two)(f)(x)

two(two(f))(x)

two(lambda y: f(f(y)))(x)

# suppose that h(y) = f(f(y))

two(h)(x)

h(h(x))

f(f(f(f(x))))   # four f

注意,这里不是 2×2 ,而是 22 ,应用外层的two时,里层翻番了

接下来,eight最外层的two又使得 4 个f翻番,于是得到 8 个f。至此,花费了如此巨大的力气,我们终于解决了这么一个特例。来之不易啊。


现在,对于任意的 n(m)与上例一样,对于里层的 m,我们记

h(x) = f(f( .. f(x) .. ))mf

于是,

n(m) = h(h( .. h(x) .. ))nh

总计 m ** nf


OK,终于搞定了。





12/27/2015

为了证明我还是太菜了,下面给出老师的解答

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

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

def church_to_int(n):
    return n(lambda x: x + 1)(0)

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

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

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




你可能感兴趣的:(Python)