为什么LISP中没有#'(尖锐引用)符号?

时间:2014-01-28 15:46:12

标签: lisp common-lisp clisp

我正在从'Practical Common Lisp'一书中学习Lisp。有一次,我应该输入以下代码:

[1] (remove-if-not #'evenp '(1 2 3 4 5 6 7 8 9 10))
(2 4 6 8 10)

我认为这里的想法当然是remove-if-not想要一个在向它提供参数时可以返回T或NIL的函数,然后将该函数应用于列表中的所有符号,返回一个列表仅包含返回NIL的符号。

但是,如果我现在在CLISP中编写以下代码:

[2] (remove-if-not 'evenp '(1 2 3 4 5 6 7 8 9 10)
(2 4 6 8 10)

它仍然有效!所以我的问题是,是否使用尖引号表示法,或仅仅使用引用是否足够?现在看起来额外的锐利只是让程序员知道“嘿,这是一个功能,而不仅仅是一些随机的符号!” - 但如果它有任何其他用途,我很想知道它。

我使用的是GNU CLISP 2.49(2010-07-07,sheesh,实际上很老)。

3 个答案:

答案 0 :(得分:12)

Sharp-quote和quote在一般情况下没有相同的行为:

(defun test () 'red)

(flet ((test () 'green))
  (list (funcall 'test)
        (funcall #'test))) => (red green)

调用带引号的符号将使用带引号的符号的函数值(即symbol-function的结果)。调用带尖括号的符号将使用符号的词法绑定(如果有)所建立的值。在公认的常见情况下,没有词汇绑定,行为将是相同的。这就是你所看到的。

你应养成使用尖锐报价的习惯。忽略函数绑定可能不是您想要的,并且可能会让任何试图理解您的代码的人感到困惑。

答案 1 :(得分:5)

这不是特定于CLISP的,它适用于每个Common Lisp实现(我在这里使用Clozure Common Lisp)。

如果您将符号设为function designator,那么实施将会为您查找symbol-function(假设符号在全局环境中可用):

? #'evenp
#<Compiled-function EVENP #x3000000F2D4F>
? (symbol-function 'evenp)
#<Compiled-function EVENP #x3000000F2D4F>

一般情况下,您可以使用其中之一,但如果稍后重新绑定被调用函数,则会产生一个有趣的效果。如果指定函数(#'(function)),则调用仍将调用旧函数,因为查找已在编译时完成;如果您使用该符号,那么您将调用新函数,因为查找是在运行时重新完成的。请注意,这可能是特定于实现的。

答案 2 :(得分:0)

正如你已经注意到(或读过)funcall等。人。将努力将您提供的函数参数转换为适当的函数。所以你已经注意到他们将采用一个符号然后获取该符号的符号函数;如果能够解决问题,他们就会调用它。

回想一下,#'X在读取时转换为(符号函数x)和'x到(引用x)。在编译时完成符号函数工作是一种很好的做法。

但为什么呢?好两个trival原因它稍快一点,它表示你不打算在编译时间后重新定义F的符号函数。另一个原因是,在Pew Research最近的一项研究中,98.3%的Lisp开发者更喜欢它,而62.3%的人会避开那些不这样做的人。

但还有更多。

'(lambda(..)...)与v.s.完全不同#'(lambda(..)...)。第一个很可能最终使用eval,即它会很慢。第一个在不同的范围内运行v.s.第二个,即只有第二个可以看到它出现的词汇范围。