问题描述
This question demonstrates that it's possible to write recursive functions without assigning them a name in the global frame.
The recursive factorial function can be written as a single expression by using a conditional expression.
>>> fact = lambda n: 1 if n == 1 else mul(n, fact(sub(n, 1)))
>>> fact(5)
120
However, this implementation relies on the fact (no pun intended) that fact
has a name, to which we refer in the body of fact
. To write a recursive function, we have always given it a name using a def
or assignment statement so that we can refer to the function within its own body. In this question, your job is to define fact
recursively without giving it a name!
Write an expression that computes n
factorial using only call expressions, conditional expressions, and lambda
expressions (no assignment or def
statements).
Note: You are not allowed to use
make_anonymous_factorial
in your return expression.
The sub
and mul
functions from the operator
module are the only built-in functions required to solve this problem.
from operator import sub, mul
def make_anonymous_factorial():
"""Return the value of an expression that computes factorial.
>>> make_anonymous_factorial()(5)
120
>>> from construct_check import check
>>> # ban any assignments or recursion
>>> check(HW_SOURCE_FILE, 'make_anonymous_factorial',
... ['Assign', 'AnnAssign', 'AugAssign', 'NamedExpr', 'FunctionDef', 'Recursion'])
True
"""
return 'YOUR_EXPRESSION_HERE'
问题分析
这道题是对与递归与lambda表达式的巧妙利用来实现不在函数体中使用def语句或赋值语句,从而通过不在global frame中绑定变量名或函数名的前提下实现递归求阶乘的方法。
首先要对lambda表达式充分理解,由 lambda表达式定义可知,lambda表达式本质上定义了一个不分配函数名的函数对象,该函数接受参数列表的参数并返回表达式的值:
lambda_expr ::= "lambda" [parameter_list] ":" expression
在之前实现阶乘的递归函数体中定义了一个函数f,通过对f的递归调用来实现求阶乘:
def factorial(n):
def f(n, f):
if n == 1:
return 1
else:
return n * f(n - 1, f)
return f(n, f)
在题目描述中,可以通过lambda表达式及赋值语句实现这个求阶乘的函数,即
fact = lambda n: 1 if n == 1 else mul(n, fact(sub(n, 1)))
如果是匿名化地实现这个阶乘函数,首先通过lambda表达式实现函数f,即
lambda x, f : 1 if x == 1 else x * f(x - 1, f)
这里实现的lambda表达式整体可以视为一个def语句实现的函数f的定义,接收的参数为x和f,即在上述阶乘函数factorial的代码实现中,这个lambda表达式等价于def语句定义的函数f。
那么在return语句中,就要用这个lambda表达式替代f,为了实现anonymous的特性,需要再次使用一个lambda表达式来接受阶乘函数外传递的参数n,并通过条件表达式实现对匿名函数(这里用lambda表达式来实现)的递归调用
代码实现
def make_anonymous_factorial():
"""Return the value of an expression that computes factorial.
>>> make_anonymous_factorial()(5)
120
>>> from construct_check import check
>>> # ban any assignments or recursion
>>> check(HW_SOURCE_FILE, 'make_anonymous_factorial',
... ['Assign', 'AnnAssign', 'AugAssign', 'NamedExpr', 'FunctionDef', 'Recursion'])
True
"""
return lambda n : (lambda x, f : 1 if x == 1 else x * f(x - 1, f))
(n, (lambda x, f : 1 if x == 1 else x * f(x - 1, f)))
当调用make_anonymous_factorial函数时,传递参数n求n的阶乘,return语句中用(lambda x, f : if x == 1 else x * f(x - 1, f))来实现函数f的定义,并将n与这个定义一起作为参数传递给它,从而实现匿名的递归调用。