16

在 Practical Common Lisp 一书的第 3 章中,有一个类似 SQL 的 select 和 where 函数的示例。这是它的简化版本:

(defun where (x) 
   #'(lambda (item)
     (> item x)))

它是这样使用的:

(remove-if-not (where 2) (list 1 2 3 4))

本书前面曾解释过,该#'序列用于说明它后跟一个函数名称,而不是需要评估的变量。我不明白为什么这里需要它。我尝试在where没有它的情况下实现该功能,并且效果也很好:

(defun where (x) 
   (lambda (item)
     (> item x)))

我试着用谷歌搜索它,你可以想象,对于这样一个字符序列,它不是一个很有成效的搜索。而且我不知道这东西的名字。上面的代码中需要它有什么特别的原因吗?

4

2 回答 2

14

这是Hyperspec中处理标准宏字符“尖锐”后跟“单引号”的精确页面。

为简单起见,此阅读器宏扩展为将以下形式包含在(function <form>)s 表达式中。这有效地告诉解析器该表单是可调用的。

lambda是一个宏,它生成的代码已经包含(function <form>),但从历史上看,为了保持一致性,也经常使用从 reader 宏中获得的另一种形式。

这是在 common lisp 中编写 lambda 表达式(另一个 StackOverflow 问题),它深入介绍了(lambda <form>)

于 2012-12-24T13:42:22.877 回答
6

注意:*print-pretty*适用NIL于这些示例。

(defun where (x) 
  #'(lambda (item)
      (> item x)))

在上面的函数where中,您正在创建一个匿名函数,并将其作为闭包返回(函数加上变量绑定X)。由于您将其作为值返回,因此您必须编写(FUNCTION (LAMBDA ...)). #'(lambda ...)是一个更短的符号,但结果相同 - 使用阅读器宏#'

CL-USER 74 > (read-from-string "#'(lambda (foo) (1+ foo))")
(FUNCTION (LAMBDA (FOO) (1+ FOO)))

你也可以写:

(defun where (x) 
  (lambda (item)
    (> item x)))

在 Common Lisp 的定义过程中添加了它以便能够编写上述代码。它也与(function (lambda ...))表格相同。在 Common LispLAMBDA中是宏,它扩展到它:

CL-USER 75 > '(lambda (foo) (1+ foo))
(LAMBDA (FOO) (1+ FOO))

CL-USER 76 > (macroexpand '(lambda (foo) (1+ foo)))
(FUNCTION (LAMBDA (FOO) (1+ FOO)))
T

因此,LAMBDA是一个宏,当评估者看到它时(lambda ...),它会将表单扩展为一个(function (lambda ...))表单,然后对其进行评估。

FUNCTION是一种特殊形式,当评估者看到它时,它会返回一个函数对象 - 在(function (lambda (foo) (1+ foo)))它返回匿名函数作为对象的情况下:

CL-USER 77 > (function (lambda (foo) (1+ foo)))
#<anonymous interpreted function 406000761C>

所以你看到这(function (lambda ...))是获取函数对象的真正的 s-expression 符号,并且#'(lambda ...)(通过阅读器宏)或(lambda ...)(通过宏)都是 Lisp 源代码中的较短符号。程序员使用长格式是不寻常的。大多数(99.999%)在源代码中使用较短的符号之一。

顺便说一句:如果评估器看到function包含这样的函数名称(function sin),那么它会查找函数绑定并返回相应的函数对象:

CL-USER 78 > (function sin)
#<Function SIN 4110083C6C>
于 2012-12-24T14:50:28.607 回答