Разница между # 'callee и' callee в Common Lisp - PullRequest
0 голосов
/ 21 мая 2018

Вот мой код 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:, кажется, указывает на некоторую тонкую разницув обоих синтаксисах: #'callee, кажется, относится к объекту функции, но 'callee, по-видимому, относится только к имени функции.

Вот мои вопросы:

  1. Что такоеРазница между синтаксисом #'callee и синтаксисом 'callee?
  2. Как получается, что funcall может успешно вызывать callee в обоих случаях?
  3. Есть ли лучшийпрактика или плюсы и минусы, связанные с обоими синтаксисами, из-за чего один предпочтительнее другого?

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

#'callee расширяется до (function callee), а 'callee расширяется до (quote callee).

#' ищет в пространстве имен функции.(Common Lisp - это 2-Lisp, что означает, что он имеет 2 отдельных пространства имен, что позволяет функции иметь то же имя, что и переменная / data - Scheme / Racket - это 1-Lisp, где функция и переменные имеют одно и то же пространство имен - то есть sthс определенным именем является либо функцией, либо именем для какого-либо другого объекта.)

' нигде не ищет, но оценивает следующее имя символа как имя.

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)>
0 голосов
/ 21 мая 2018

Разница во многом заключается в том, как выглядит функция.Если передать символ 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)
...