首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在常见的lisp中,FUNCALL和#'function-name有什么区别?

在常见的lisp中,FUNCALL和#'function-name有什么区别?
EN

Stack Overflow用户
提问于 2012-03-08 13:39:52
回答 2查看 2.3K关注 0票数 5

我正在阅读一本书的家庭作业,我理解使用#‘是将变量视为函数而不是变量。但我在FUNCALL上有点糊涂。我知道lisp是用变量来创建对象的,那么函数名只是一个“指针”(可能是一个不好的词,但希望你明白我的意思),在这种情况下,你可以使用#‘来调用它,或者funcall是调用它们的唯一方法?例如。

代码语言:javascript
复制
(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 "~%")))

我就不能这样做:

代码语言:javascript
复制
(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 "~%")))

我想我的困惑在于函数名到底是什么。当我读这本书的时候,它说变量的值就是函数对象。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-08 14:58:36

#'function-name(function function-name)。不调用任何东西,计算任何一个结果都会得到与function-name关联的函数(表示该函数的对象)。funcall用于调用函数。

请参见HyperSpec中的funcallfunction

同时使用以下两种方法的示例会话:

代码语言:javascript
复制
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)
9

funcall的第二次调用之所以有效,是因为它还接受一个符号作为函数指示符(有关详细信息,请参阅上面的funcall链接)。

票数 13
EN

Stack Overflow用户

发布于 2012-03-08 16:04:53

在Common Lisp中需要使用#'funcall符号,因为这种语言是所谓的"Lisp-2“,其中给定的符号可以有两个独立且不相关的主要”含义“,通常如下所示

  1. 用作表单的第一个元素时,表示
  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)将相关的函数作为值返回,您可以将其存储在变量中或进行传递:

代码语言:javascript
复制
(defvar *fn* #'square)

例如,在上面的代码中,变量*fn*将接收前面定义的函数。函数值可以像任何其他值一样进行操作,如字符串或数字。

funcall正好相反,它允许不使用函数名而是使用值来调用函数。

代码语言:javascript
复制
(print (funcall *fn* 12))

上面的代码将显示144...因为存储在变量*fn*中的函数现在被调用,传递12作为参数。

如果你知道"C“编程语言,一个类比就是认为(let ((p #'square))...)就像获取函数square的地址(就像{ int (*p)(int) = &square; ...}一样),而(funcall p 12)就像使用指针调用函数(就像"C”允许缩写为p(12)(*p)(12)一样)。

Common Lisp中不可否认的令人困惑的部分是,您可以在同一个作用域中同时拥有一个名为square的函数和一个名为square的变量,并且该变量不会隐藏该函数。当您需要将变量的值用作函数或希望将函数用作值时,可以分别使用funcallfunction这两个工具。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9613376

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档