我正在阅读一本书的家庭作业,我理解使用#‘是将变量视为函数而不是变量。但我在FUNCALL上有点糊涂。我知道lisp是用变量来创建对象的,那么函数名只是一个“指针”(可能是一个不好的词,但希望你明白我的意思),在这种情况下,你可以使用#‘来调用它,或者funcall是调用它们的唯一方法?例如。
(defun plot (fn min max step)
(loop for i from min to max by step do
(loop repeat (funcall fn i) do (format t "*"))
(format t "~%")))我就不能这样做:
(defun plot (fn min max step)
(loop for i from min to max by step do
(loop repeat #'(fn i) do (format t "*"))
(format t "~%")))我想我的困惑在于函数名到底是什么。当我读这本书的时候,它说变量的值就是函数对象。
发布于 2012-03-08 14:58:36
#'function-name是(function function-name)。不调用任何东西,计算任何一个结果都会得到与function-name关联的函数(表示该函数的对象)。funcall用于调用函数。
请参见HyperSpec中的funcall和function。
同时使用以下两种方法的示例会话:
CL-USER> (defun square (x) (* x x))
SQUARE
CL-USER> #'square
#<FUNCTION SQUARE>
CL-USER> (function square)
#<FUNCTION SQUARE>
CL-USER> (funcall #'square 3)
9
CL-USER> (funcall 'square 3)
9funcall的第二次调用之所以有效,是因为它还接受一个符号作为函数指示符(有关详细信息,请参阅上面的funcall链接)。
发布于 2012-03-08 16:04:53
在Common Lisp中需要使用#'和funcall符号,因为这种语言是所谓的"Lisp-2“,其中给定的符号可以有两个独立且不相关的主要”含义“,通常如下所示
变量
这些是大致的解释,您将在下面的示例中看到,“表单的第一个元素”和“任何其他位置”都不是正确的定义。
请考虑以下示例:

上面的代码打印144...乍一看可能令人惊讶,但原因是使用相同名称的平方有两种不同的含义:给定参数的函数返回参数与自身相乘的结果,以及局部变量square的值为12。
第一次和第三次使用square这个名字,意思是名为square的函数,我把这个名字涂成了红色。第二次和第四次使用是关于一个名为square的变量,并且被涂成蓝色。
Common Lisp如何决定哪一个是哪一个?重点是位置。在defun之后,它显然是本例中的函数名,就像(square square)的第一部分中的函数名一样。同样,作为let表单中列表的第一个元素,它显然是一个变量名,在(square square)的第二部分中也是一个变量名。
这看起来很疯狂..。不是吗?在Lisp社区中确实存在一些分歧,关于这种双重含义是会让事情变得更简单还是更复杂,这也是Common Lisp和Scheme之间的主要区别之一。
不深入细节,我只想说,这个明显疯狂的选择是为了使Lisp宏更有用,提供了足够的安全性,使它们可以很好地工作,而不会增加复杂性,也不会消除完全健康的宏的表现力。可以肯定的是,这是一个复杂的问题,使得向正在学习它的人解释它变得更加困难(这就是为什么Scheme被认为是一种更好(更简单)的教学语言),但许多专家lisper认为这是一个很好的选择,使Lisp语言成为解决实际问题的更好工具。
此外,在人类语言中,上下文扮演着重要的角色,有时同一个词可以有不同的含义,这对人类来说并不是一个严重的问题(例如,作为名词或动词,如"California is the state I live in“或"State your opinion")。
然而,即使在Lisp-2中,也需要使用函数作为值,例如将它们作为参数传递或存储到数据结构中,或者需要将值作为函数使用,例如调用作为参数接收的函数(您的绘图用例)或存储在某个地方的函数。这就是#'和funcall发挥作用的地方……
#'foo确实只是(function foo)的快捷方式,就像'x是(quote x)的快捷方式一样。这个“函数”是一种特殊的形式,给定一个名称(在本例中为foo)将相关的函数作为值返回,您可以将其存储在变量中或进行传递:
(defvar *fn* #'square)例如,在上面的代码中,变量*fn*将接收前面定义的函数。函数值可以像任何其他值一样进行操作,如字符串或数字。
funcall正好相反,它允许不使用函数名而是使用值来调用函数。
(print (funcall *fn* 12))上面的代码将显示144...因为存储在变量*fn*中的函数现在被调用,传递12作为参数。
如果你知道"C“编程语言,一个类比就是认为(let ((p #'square))...)就像获取函数square的地址(就像{ int (*p)(int) = □ ...}一样),而(funcall p 12)就像使用指针调用函数(就像"C”允许缩写为p(12)的(*p)(12)一样)。
Common Lisp中不可否认的令人困惑的部分是,您可以在同一个作用域中同时拥有一个名为square的函数和一个名为square的变量,并且该变量不会隐藏该函数。当您需要将变量的值用作函数或希望将函数用作值时,可以分别使用funcall和function这两个工具。
https://stackoverflow.com/questions/9613376
复制相似问题