如何理解Peter Norvig的Python函数式代码?

时间:2013-01-17 01:52:11

标签: python lambda

在阅读Peter Norvig的Python IAQ时,我遇到了这段代码:

def _if(test):
    return lambda alternative: \
               lambda result: \
                   [delay(result), delay(alternative)][not not test]()
def delay(f):
    if callable(f): return f
    else: return lambda: f
fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1))
fact(100)

我在互联网上搜索了这个代码,这个代码出现在几个论坛中,但似乎那些评论它的人都理解它是如何工作的。

我对函数式编程概念很陌生。我知道如果测试评估为True,则会选择delay(alternative)。但实际上,如果test为true,则返回结果。这对我来说似乎是违反直觉的。

2 个答案:

答案 0 :(得分:5)

让我们看看:

    调用
  • _if(True),并立即返回带有alternative参数
  • 的lambda
  • 调用返回的lambda,alternative设置为1并返回result lambda
  • 调用result lambda,result设置为lambda: n * fact(n-1)
  • not not True求值为1(此示例来自python 2.4时代!),它为第二个列表项索引,即delay(alternative)
  • alternative之前已设置为1
  • 调用
  • delay(1),返回lambda: 1
  • lambda: 1被调用,它返回1

TL / DR:1alternative

命名函数版本:

def _if(test):
    def then_closure(expr_if_true):
        def else_closure(expr_if_false):
            if test:
                delayed = delay(expr_if_true)
            else:
                delayed = delay(expr_if_false)
            return delayed()
        return else_closure
    return then_closure

答案 1 :(得分:1)

反过来。

fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1))
fact(100)

第一个函数减少到[_if(100 <= 1)]并且它在两个函数[(1)]和[(lambda:n * fact(n-1))]之间进行选择。如前所述,True函数调用第二个函数,False调用第一个函数。因此调用第二个函数并将lambda评估为:

lambda: 100 * fact(99)

请注意,延迟功能有效对此情况无效。整个过程从事实(99)重新开始:

fact(99) =  lambda n: _if (99 <= 1) (1) (lambda: 99 * fact(98))

再次,_if函数调用为True,它触发第二个函数调用,然后调用另一个事实(98),依此类推。

堆栈慢慢堆积起来:

100 * fact(99) 
100 * 99 * fact(98)
100 * 99 * 98 * fact(97)

特殊情况是事实(1):

fact(1) = lambda n: _if (1 <= 1) (1) (lambda: 1 * fact(0))

因为_if现在是False,所以第一个函数被传递给delay,它将它转换为函数并调用它,返回1并允许堆栈解析。发生乘法并给出结果(100!)。