2012-03-08 67 views
5

我正在阅读一本书作家庭作业,并且我明白使用#'会将该变量视为一个函数而不是一个变量。但是我对FUNCALL有点朦胧。我明白,lisp使变量的对象,所以功能名称只是一个'指针'(可能是一个坏词,但希望你明白我的意思),在这种情况下,你使用#'来调用它,或者是funcall唯一的方法来调用它们?恩。FUNCALL和#'function-name in common lisp有什么区别?

(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 "~%"))) 

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

回答

13

#'function-name(function function-name)。什么都没有被调用,评估与function-name(表示函数的对象)相关的函数中的结果。 funcall用于调用函数。

参见funcallfunctionHyperSpec。同时使用

样品会话:

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)。

8

#'funcall符号需要Common Lisp中,因为此语言是一种所谓的“Lisp的-2”,其中一个给定的符号可以具有两个独立的和不相关的主要的“含义”常列为

  1. 当作为一种形式的第一元件中使用它的意思的函数
  2. 当在任何其他地方使用它意味着一个可变

这些都是近似的解释,因为你将在下面的例子中看到,“第一EL表达形式“和”任何其他地方“都不是正确的定义。

考虑例如:

lisp-2

上面的代码打印144 ...它可能一开始会感到奇怪,但原因是相同的名称square使用两种不同的含义:功能给定一个参数返回自变量乘以自变量与局部变量平方的值为12的结果。

名称的第一个和第三个用途square的含义是函数名为square,我用红色画了这个名字。第二个和第四个用途代替变量,名称square,并用蓝色代替。

Common Lisp如何决定哪个是哪个?重点是位置......在defun之后,很明显在这种情况下是一个函数名称,例如它是(square square)的第一部分中的函数名称。同样,作为let表单中的第一个元素,它显然是一个变量名称,它也是(square square)第二部分中的一个变量名称。

这看起来很精神......不是吗?那么Lisp社区确实存在一些分裂,这个双重含义是否会使事情变得更简单或更复杂,这是Common Lisp和Scheme之间的主要区别之一。

没有深入细节,我只是说这显然是疯狂的选择,已经使Lisp宏变得更加有用,提供了足够的卫生,使它们很好地工作,没有增加的复杂性和完全卫生的宏的删除表现力。可以肯定的是,这是一种复杂化,使得向谁学习它的人解释语言变得更加困难(这就是为什么Scheme被认为是更好(更简单)的教学语言的原因),但许多专家级的Lispers认为这是一个很好的选择,它使得Lisp语言成为解决实际问题的更好工具。

同样在人类语言中,上下文无论如何都扮演着重要的角色,对于人类来说这不是一个严重的问题,有时候同一个词可以用于不同的含义(例如作为名词或动词,如“加利福尼亚州状态我住“或”陈述你的意见“)。即使在Lisp-2中,您也需要使用函数作为值,例如将它们作为参数传递或将它们存储到数据结构中,或者您需要使用值作为函数,例如调用已经存在的函数作为参数(您的情节大小写)或已经存储在某处。这是#'funcall发挥作用......

#'foo确实只是(function foo)一个快捷方式,酷似'x(quote x)一个快捷方式。这种“功能”的是(在这种情况下foo)给出的名称返回相关的功能作为一种价值的一种特殊形式,你可以在变量存储或绕过:在例如上面的代码

(defvar *fn* #'square) 

变量*fn*将接收之前定义的函数。函数值可以像任何其他值一样被操纵,如字符串或数字。

funcall是相反的,从而允许调用一个函数不使用它的名字,但通过使用值...

(print (funcall *fn* 12)) 

上面的代码将显示144 ...因为已存储在功能变量*fn*现在被称为传递12作为参数。

如果你知道一个比喻是考虑(let ((p #'square))...)喜欢拍照的功能square的地址(如{ int (*p)(int) = &square; ...}),而是(funcall p 12)就像使用指针(如(*p)(12)是“C”调用函数“C”编程语言允许缩写为p(12))。

Common Lisp中容易引起混淆的部分是,您可以在同一范围内同时使用名为square的函数和名为square的变量,并且该变量不会隐藏该函数。 funcallfunction是您可以在需要将变量的值用作函数或将函数分别用作值时使用的两种工具。

+4

我认为你的解释可能不太“神秘”,如果你已经使用了“namespace”这个词而不是“含义”这个模糊的词。 CL是一个Lisp-2,这意味着符号可以出现在两个名称空间中,每个名称空间中都有不同的值。即符号'foo'可以在值名称空间中具有值42(您可以使用'symbol-value'查看它的值),并且它也可以具有值'(lambda(x)(1 + x))'在函数名称空间('symbol-function')中。 – Daimrod 2012-03-08 09:03:47

+0

谢谢你。我很好奇。在你的情况下,你将函数传递给一个全局变量。如果你有这个功能,你可不可以这样做(\ * fn \ * 12)?或者只是对于作为函数存在的平方函数而言? – Andy 2012-03-08 21:55:47

+0

@Andy:形式'(* fn * 12)'表示通用lisp“调用名为'* fn *'的函数传递12作为参数”...被调用的函数在逻辑上是固定的,甚至可以内联通过编译器:是函数'(defun * fn *(x)...)'。以相同方式命名的变量是另一个不相关的东西,可以包含任何值...例如数字,字符串或函数的地址。形式'(funcall * fn * 12)'意味着“调用其地址包含在名为'* fn *'的变量中的函数”。另一方面,'#'square'或多或少地意味着“函数'square'的地址”。 – 6502 2012-03-09 06:55:52

相关问题