8

在阅读 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)

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

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

4

2 回答 2

5

让我们来看看:

  • _if(True)被调用,并立即返回一个带有alternative参数的 lambda
  • 返回的 lambda 用alternativeset to调用1并返回resultlambda
  • lambda被result调用并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
于 2013-01-17T02:03:15.387 回答
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)

请注意,延迟函数有效对于这种情况没有任何作用。整个过程从 fact(99) 重新开始:

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

_if 函数调用再次为 True,它触发第二个函数调用,然后调用另一个 fact(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!)。

于 2013-01-17T02:12:03.647 回答