在阅读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,则返回结果。这对我来说似乎是违反直觉的。
答案 0 :(得分:5)
让我们看看:
_if(True)
,并立即返回带有alternative
参数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:1
是alternative
。
命名函数版本:
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!)。