gpt4 book ai didi

lisp - Lisp(Allegro Common Lisp)如何在 ' vs #' 的 lambda 中使用变量

转载 作者:行者123 更新时间:2023-12-04 22:34:17 30 4
gpt4 key购买 nike

我希望有人能解释为什么测试 1-5 有效而测试 6 无效。我认为用 ' 引用 lambda 并在 lambda 前面使用 #' 都会返回指向函数的指针,唯一的区别是 #' 将首先编译它。

(defun test-1 (y)
(mapcar (lambda (x) (expt x 2))
'(1 2 3)))

(defun test-2 (y)
(mapcar (lambda (x) (expt x y))
'(1 2 3)))

(defun test-3 (y)
(mapcar #'(lambda (x) (expt x 2))
'(1 2 3)))

(defun test-4 (y)
(mapcar #'(lambda (x) (expt x y))
'(1 2 3)))

(defun test-5 (y)
(mapcar '(lambda (x) (expt x 2))
'(1 2 3)))

(defun test-6 (y)
(mapcar '(lambda (x) (expt x y))
'(1 2 3)))

我使用的是免费版的 Franz Industries Allegro Common Lisp。以下是输出:

(test-1 2)     ; --> (1 4 9)
(test-2 2) ; --> (1 4 9)
(test-3 2) ; --> (1 4 9)
(test-4 2) ; --> (1 4 9)
(test-5 2) ; --> (1 4 9)
(test-6 2) ; --> Error: Attempt to take the value of the unbound variable `Y'. [condition type: UNBOUND-VARIABLE]

最佳答案

首先,您应该知道您的测试 1-4 符合 Common Lisp,而您的测试 5 和 6 不符合。我相信 Allegro 完全可以做它为 5 和 6 做的事情,但它所做的超出了标准。标准中谈到这一点的是像 mapcar 这样的函数的定义。 , 以函数指示符 作为参数,以及 function designator 的定义:

function designator n. a designator for a function; that is, an object that denotes a function and that is one of: a symbol (denoting the function named by that symbol in the global environment), or a function (denoting itself). The consequences are undefined if a symbol is used as a function designator but it does not have a global definition as a function, or it has a global definition as a macro or a special form. [...]

从这里可以清楚地看出,像 (lambda (...) ...) 这样的列表不是函数指示符:它只是一个列表,其汽车恰好是 lambda . Allegro 正在做的是注意到这个列表实际上是可以转化为函数的东西,并这样做。

好吧,让我们写一个版本的mapcar Allegro 的功能:

(defun mapcar/coercing (maybe-f &rest lists)
(apply #'mapcar (coerce maybe-f 'function) lists))

这只使用 coerce 这是一个知道如何将这样的列表转换为函数的函数。如果它的参数已经是一个函数,coerce只是返回它。

现在我们可以使用这个函数编写两个测试:

(defun test-5/coercing (y)
(mapcar/coercing '(lambda (x) (expt x 2))
'(1 2 3)))

(defun test-6/coercing (y)
(mapcar/coercing '(lambda (x) (expt x y))
'(1 2 3)))

那么,在序言之后,为什么不能 test-6/explicit工作?好吧,答案是 Common Lisp 是(特殊变量除外)词法作用域词法作用域 只是一种奇特的说法,表示可用的绑定(bind)(变量)完全是并且只有您可以通过查看程序源代码看到 的绑定(bind)。 (除了用于特殊绑定(bind)的 CL,我将忽略它,因为这里没有。)

因此,考虑到这一点,考虑 test-6/coercing ,特别是对 mapcar/coercing 的调用:在那次通话中,coerce不得不翻榜(lambda (x) (expt z y))成一个函数。所以它就是这样做的。但它返回的函数不绑定(bind) y y 没有绑定(bind)其中可见:函数使用 y “免费”。

唯一可行的方法是 coerce 的函数我们的构造是动态寻找y的绑定(bind).好吧,这就是动态范围语言所做的,但 CL 不是动态范围的。

也许使这一点更清楚的一种方法是认识到我们可以直接从函数中提取函数创建:

(defun test-7 (y f)
(mapcar f '(1 2 3)))

> (test-7 1 (coerce '(lambda (x) (expt x y)) 'function))

很明显,这在词法范围的语言中是行不通的。

那么,测试 1-4 是如何工作的?

嗯,首先这里实际上只有两个测试。在 CL 中,lambda是一个宏并且(lambda (...) ...)完全等同于(function (lambda (...) ...)) .当然还有#'(lambda (...) ...) (function (lambda (...) ...))相同: 它只是一个读取宏。

(function ...)是一个神奇的东西(一种特殊形式),它说“这是一个函数”。关于 function 的重要事项是它不是一个函数:它是一个非常神奇的东西,它告诉计算器(或编译器)它的参数是函数的描述在当前词法上下文中,所以,例如在 p>

(let ((x 1))
(function (lambda (y) (+ x y))))

x此创建的函数引用的是 x受约束 let .所以在你的测试 2 和 4(它们是相同的)中:

(defun test-4 (y)
(mapcar (function (lambda (x) (expt x y)))
'(1 2 3)))

y的绑定(bind)创建的函数引用的是 y 的绑定(bind)这是词汇可见的,这是 test-4 的参数本身。

关于lisp - Lisp(Allegro Common Lisp)如何在 ' vs #' 的 lambda 中使用变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64308742/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com