【问题标题】:The #' in common lisp#' 常见的 lisp
【发布时间】:2012-12-10 21:53:49
【问题描述】:

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

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

【问题讨论】:

标签: common-lisp quote


【解决方案1】:

这是精确的page in Hyperspec,它处理标准宏字符“尖”,后跟“单引号”。

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

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

这是Writing lambda expressions in common lisp(另一个 StackOverflow 问题),它深入介绍了 (lambda <form>) 的特殊情况

【讨论】:

  • 具体来说,#'(lambda () nil) 不是宏调用,而是函数字面量,并且 (lambda () nil) 调用扩展为 #'(lambda () nil 的宏扩展器)。
【解决方案2】:

注意:对于这些示例,*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 Lisp 中,LAMBDA 是宏,它会扩展为它:

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 表达式表示法,#'(lambda ...)(通过读取器宏)或(lambda ...)(通过宏)在 Lisp 源代码中都是较短的表示法。程序员使用长格式是不寻常的。大多数 (99.999%) 在源代码中使用较短的符号之一。

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

CL-USER 78 > (function sin)
#<Function SIN 4110083C6C>

【讨论】:

  • 当我尝试在 REPL 中运行您的代码时,得到的结果略有不同。 # 似乎没有被 function 取代。特别是(read-from-string "#'(lambda (foo) (1+ foo))") 导致#'(LAMBDA (FOO) (1+ FOO))(macroexpand '(lambda (foo) (1+ foo))) 导致#'(LAMBDA (FOO) (1+ FOO))。我正在使用 Lisp in a Box 和 Clozure Common Lisp。
  • @Max:当*print-pretty*T 时,它会尝试以这种方式打印。将*print-pretty* 设置为NIL 并重试...
  • 我刚刚检查了 print-pretty 是 nil
  • 在 CCL 中也使用 (setf *PRINT-ABBREVIATE-QUOTE* nil).
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-13
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多