我有这个问题:
cons(a, b)
构造一对,car(pair)
和cdr(pair)
返回该对的第一个和最后一个元素。例如,car(cons(3, 4))
返回3
,而cdr(cons(3, 4))
返回4
。给出此缺点的实现:
def cons(a, b): def pair(f): return f(a, b) return pair
实施
car
和cdr
。
我没有功能。
它具有一个内部函数,并在返回中调用另一个函数。据我了解,内部功能是这些功能应取决于它们上面的功能。在这种情况下,cons(..)
。
但是该函数未使用a
或b
。为何函数f
在那里?任务是实现car
和cdr
,并应指定功能f
。
那么有人可以向我解释这个功能吗?我该如何开始这项任务?
答案 0 :(得分:5)
首先:Python函数对象是一流的对象。 def
语句会生成一个新的函数对象,您可以使用函数名称来检索该对象:
>>> def foo():
... return 'foo was called'
...
>>> foo
<function foo at 0x11b3d8ae8>
这意味着您也可以将该对象分配给其他名称,并且可以将它们作为参数传递给函数调用。然后,您可以通过在引用中添加(...)
来调用函数对象:
>>> bar = foo
>>> bar()
'foo was called'
在当前名称空间中将函数名称分配给该名称。在模块中,这是全局变量,但是在诸如cons
之类的函数中,该名称被添加为本地名称。 return pair
函数中的cons
然后将函数对象pair
返回给调用者。
f
和a
和b
等函数参数也是变量;如果将函数对象作为参数传递,则parameter_name(...)
将调用paramater_name
并传递...
部分中的所有参数。 f(a, b)
呼叫f
,并传入a
和b
。
下一个要了解的项目是closures;闭包是附加到函数对象上的额外名称空间,用于来自周围范围的变量。
在下面的示例中,spam
是bar
函数闭包中的名称:
>>> def foo():
... spam = 'Vikings'
... def bar():
... return spam
... return bar
...
>>> foo()
<function foo.<locals>.bar at 0x11b44bf28>
>>> foo()()
'Vikings'
调用foo()
返回一个新的函数对象; bar()
内部的foo()
函数。调用返回的函数对象将生成'Vikings'
,即spam
函数中foo
变量的值。 bar()
是如何获得此权限的?通过关闭:
>>> foo().__closure__
(<cell at 0x11b3c05b8: str object at 0x11b469180>,)
>>> foo().__closure__[0].cell_contents
'Vikings'
因此嵌套函数可以通过闭包访问周围范围的名称。 (注意:不是 value 存储在闭包中,而是 variable 。该变量可以随时间变化,就像以后访问该名称的其他变量会反映出来一样新值;如果以后更改了spam
,则再次调用bar()
将返回新值)。
现在使用您的函数:cons()
创建一个内部函数pair()
,pair()
可以通过其闭包访问参数a
和b
:< / p>
>>> def cons(a, b):
... def pair(f):
... return f(a, b)
... return pair
...
>>> cons(42, 81)
<function cons.<locals>.pair at 0x11b46f048>
>>> pair_42_81 = cons(42, 81)
>>> pair_42_81.__closure__
(<cell at 0x11b3c02b8: int object at 0x10f59a750>, <cell at 0x11b3c05b8: int object at 0x10f59ac30>)
>>> pair_42_81.__closure__[0].cell_contents
42
>>> pair_42_81.__closure__[1].cell_contents
81
pair()
函数使用参数f
,然后调用该参数,并传入a
和b
。让我们看看传入print
时会发生什么。
print
也是一个函数,它是您可以调用的对象,并且将参数写入控制台,并在两者之间留有空格:
>>> print
<built-in function print>
>>> print('arg1', 'arg2')
arg1 arg2
如果将其传递给pair()
返回的cons()
函数,则可以看到f(a, b)
的作用:
>>> pair_42_81(print)
42 81
传递给print
的 pair()
被分配给f
,并且f(a, b)
与print(a, b)
完全相同。
我们可以看到调用print()
是因为将值写到了控制台。但是您也可以创建一个返回新值的函数。假设您有一个将两个数字相加并返回该值的函数:
>>> def add(first, second):
... return first + second
...
>>> add(42, 81)
123
>>> pair_42_81(add)
123
我们可以直接调用该函数,然后返回123
,也可以让pair_42_81()
为我们完成该操作,并返回相同的结果。简单!
所有这些都有效,因为函数是对象,可以像其他变量一样传递,并且因为pair_42_81
的{{1}}和a = 42
存储在闭包中,并将使用它们来调用a给定对象c = 81
和这两个参数。
下一个是f
和cdr()
,它们将返回一对中的第一个或最后一个元素。如果car()
产生cons(a, b)
返回pair(f)
,则f(a, b)
和cdr()
必须分别创建一个传递给car()
的函数,该函数将提取{ {1}}或pair()
。
因此在每个函数中创建一个嵌套函数,并分别用该函数a
和b
调用cdr()
。嵌套函数完成选择car()
或pair()
的工作,并返回该值。然后将通话结果返回给外界:
a
b
调用def car(pair):
def return_first(a, b):
return a
return pair(return_first)
def cdr(pair):
def return_last(a, b):
return b
return pair(return_last)
,返回pair(return_first)
,return_first(a, b)
可以将其返回给呼叫者:
a
car()
同样适用,仅现在返回>>> car(cons(42, 81))
42
:
pair(return_last)
您可能对这些操作的背景感兴趣; b
,>>> cdr(cons(42, 81))
81
和car
来自LISP,其中cdr
构造一个具有两个指针(说明名称)的单元格,而{{1 }}(表示创建LISP的IBM 704指令集中的寄存器编号的地址部分的内容)和cons
(表示寄存器的减量部分的内容的 704语言中的数字)。参见this Wikipedia article on the names。
答案 1 :(得分:2)
这称为关闭。两个基本要素
pair
函数知道a
和b
的值。在这方面,它们就像局部变量一样cons
函数返回一个函数,而不是值。您必须再次调用结果因此,当您调用cons(a, b)
时,您会得到一个对a
和b
做某事的函数,只是它还不知道什么。您必须为此传递另一个函数。例如
my_f = cons(1, 2)
result = my_f(lambda x, y: x + y)
print(result) # 3
这与您的作业有何关系尚不清楚。我仅假设,对于car
,您只想要元素a
(头部),对于cdr
,您想要元素b
(列表的其余部分)。因此,这些函数只会返回一个参数而忽略另一个参数。例如
car_f = lambda x, y: x
cdr_f = lambda x, y: y
答案 2 :(得分:1)
cons
是一个带有两个参数a
和b
的函数,并返回一个函数pair
。
函数pair
以函数f
作为参数,它消耗两个参数。
def cons(a, b):
def pair(f):
return f(a, b)
return pair
f = lambda n, m: n**2 + m**3
car = lambda n, m: n
cdr = lambda n, m: m
print(cons(2, 3)(f))
print(cons(2, 3)(car))
print(cons(2, 3)(cdr))
f
返回31 = 2**2 + 3**3
请注意,cons
的括号是(...)
的两倍-一次用于自己的调用,另一次用于返回的函数调用。
请注意this answer才能呼叫car(cons(2, 3))
。您可能还对Why would a program use a closure?
答案 3 :(得分:0)
我手动转换了cons
函数的Javascript版本,然后实施了测验:
cons(a,b)构造一个对,car(pair)和cdr(pair)返回该对的第一个和最后一个元素。例如,car(cons(3,4))返回3,而cdr(cons(3,4))返回4。给出cons的以下实现:
def cons(a, b):
def pair(f):
return f(a, b)
return pair
实施汽车和cdr。
这是解决方案
function cons(a, b) {
function pair(f) {
return f(a, b);
}
return pair;
}
function car(pair) {
return pair((a, b) => a);
};
function cdr(pair) {
return pair((a, b) => b);
};
console.log(car(cons(3,4)));
console.log(cdr(cons(3,4)));