Common Lisp中#'被调用者和'被调用者之间的区别

时间:2018-05-21 14:38:17

标签: function lisp common-lisp

这是我的Common Lisp代码:

(defun caller (f)
  (format t "caller: f: ~a~%" f)
  (funcall f 10))

(defun callee (x)
  (format t "callee: x: ~a~%" x))

(caller #'callee)
(caller 'callee)

以下是我使用clisp获得的输出:

$ clisp foo.lisp 
caller: f: #<FUNCTION CALLEE (X) (DECLARE (IN-DEFUN CALLEE)) (BLOCK CALLEE (FORMAT T callee: x: ~a~% X))>
callee: x: 10
caller: f: CALLEE
callee: x: 10

我想知道语法#'callee和语法'callee之间的区别。

虽然使用这两种语法,但我能够将callee传递给caller,但caller: f:输出似乎表明两种语法都有一些细微差别:{{ 1}}似乎引用了一个函数对象,但#'callee似乎只引用了函数名。

以下是我的问题:

  1. 'callee语法与#'callee语法之间的区别是什么?
  2. 'callee如何在两种情况下成功调用funcall
  3. 是否存在与这两种语法相关的最佳实践或优缺点,因为哪种语法优先于另一种语法?

2 个答案:

答案 0 :(得分:1)

差异主要在于如何查找功能。如果将符号传递给funcall,则会在全局(而不是词汇)环境中查找。相关文档为http://clhs.lisp.se/Body/f_funcal.htm。我稍微修改了文档中的示例:

(defun cons* (&rest rest)
  (apply 'cons rest))

(flet ((cons* (x y) `(kons ,x ,y)))
  (let ((cons* (symbol-function '+)))
    (funcall #'cons*
         (funcall 'cons* 1 2)
         (funcall cons* 1 2))))

;; => (KONS (1 . 2) 3)

答案 1 :(得分:1)

#'callee扩展为(function callee),而'callee扩展为(quote callee)

#'在函数名称空间中查找。 (Common Lisp是一个2-Lisp,意味着它有2个独立的命名空间,允许函数可以具有相同的名称,如变量/数据 - Scheme / Racket是1-Lisp,其中函数和变量共享相同的命名空间 - 意思是......具有特定名称的是某个其他对象的函数或名称。)

'不会在任何地方查找,但会将以下符号名称评估为自己的名称。

funcall在函数名称空间中查找其参数名称,并返回分配给它的函数。如果执行普通函数调用(callee 10),则Lisp解释器会从函数名称空间中隐式查找callee,因为列表中的第一个位置是为函数名保留的。当函数名作为参数给出时,在除第一个之外的其他位置,您必须首先对它们应用funcall#',以便解释器知道它必须在函数名称空间中查找该名称而不是在正常的变量名称空间。

试试这个:

(defun d (x) x) ;; declares a function d in the function name space
(setf d 1)      ;; declares variable d in the variable name space
(list d #'d d #'d)
;; returns:
(1 #<FUNCTION D (X) (DECLARE (SYSTEM::IN-DEFUN D)) (BLOCK D X)> 1
#<FUNCTION D (X) (DECLARE (SYSTEM::IN-DEFUN D)) (BLOCK D X)>)
;; when `#'` is given, the d is looked up from the function name space,
;; without, d is looked up from the normal variable name space
(d d)
;; the first position d gets looked up from the function name space but 
;; the argument d from the variable name space
;; since the function d is the identity function and variable d has the value 1,
;; this evaluates the identity function on 1, thus to
1
(d #'d) ;; now the argument `d` is looked up from the function name space
;; thereby returning a function:
#<FUNCTION D (X) (DECLARE (SYSTEM::IN-DEFUN D)) (BLOCK D X)>