Когда следует использовать острые кавычки?

10

Я вижу острые кавычки, используемые в коде eLisp других людей, и использую их сам, но я не совсем понимаю, когда они уместны, а когда нет.

Может ли кто-нибудь уточнить, когда именно целесообразно использовать острые кавычки и когда вместо них следует использовать обычные одинарные кавычки?

izkon
источник
3
nb Есть много дубликатов для этого вопроса здесь или на SO
phils
Возможный дубликат Когда указывать лямбда-выражение?
Эндрю Суонн
1
Я не думаю, что это дубликат: emacs.stackexchange.com/questions/3595 об использовании #'с лямбда- выражением (где ответ в основном «никогда»), тогда как вопрос @ izkon относится скорее к использованию #'применительно к символам.
Стефан

Ответы:

12

#'это просто сокращение для function, так же, как 'сокращение для quote.

Вы можете использовать его в любом месте, где хотите указать байтовому компилятору, интерпретатору или читателю-человеку, что его аргумент, как ожидается, будет (рассматривается как) функция.

Во многих контекстах контекст определяет, как обрабатывается аргумент, если, например, вы просто заключаете его в кавычки (используйте quoteили ') вместо использования #'(или function). Например, в контексте, где символ используется только для его symbol-functionсвойства, то есть он используется как функция, вы можете просто передать символ (например, заключив его в кавычки или передав переменную, значение которой является символом).

Но иногда код становится понятнее, если вы используете его #'в таком контексте. Даже если сам Emacs-Lisp понимает, что символ используется как функция в таких контекстах, это может помочь подчеркнуть это для читателя кода.

В некоторых других Лиспах обработка лямбда-форм, которые просто заключаются в кавычки (с ') или не заключаются в кавычки, могут отличаться от их использования в функциональной позиции при цитировании с использованием function( #'). Но не в Emacs Lisp. В Emacs Lisp вам не нужно заключать в кавычки (используя либо 'или #') лямбда-форму, которую вы хотите обрабатывать как функцию (а не просто как список). Если вы хотите, чтобы он обрабатывался как список, с автомобилем lambdaи т. Д., Укажите его (с ') - пример, приведенный ниже, иллюстрирует это.

От (elisp) анонимных функций :

- Специальная форма: function function-object

Эта специальная форма возвращается FUNCTION-OBJECTбез оценки.

В этом он похож на quote(* примечание цитирования: :). Но в отличие от этого quote, он также служит примечанием для оценщика Emacs и байтового компилятора, который FUNCTION-OBJECTпредназначен для использования в качестве функции. Предполагая, что FUNCTION-OBJECTявляется допустимым лямбда-выражением, это имеет два эффекта:

• Когда код компилируется байтом, FUNCTION-OBJECTкомпилируется в объект функции байтового кода (* note By By Compilation: :).

• Когда лексическое связывание включено, FUNCTION-OBJECTпреобразуется в замыкание. * Примечание Закрытия ::.

Синтаксис чтения #'является сокращением для использования function. Следующие формы все эквивалентны:

(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))

В следующем примере мы определяем change-propertyфункцию, которая принимает функцию в качестве третьего аргумента, а затем double-property функцию, которая использует ее change-property, передавая ей анонимную функцию:

(defun change-property (symbol prop function)
   (let ((value (get symbol prop)))
     (put symbol prop (funcall function value))))

(defun double-property (symbol prop)
   (change-property symbol prop (lambda (x) (* 2 x))))

Обратите внимание, что мы не цитируем lambdaформу.

Если вы скомпилируете приведенный выше код, анонимная функция также скомпилируется. Этого бы не произошло, если бы, скажем, вы создали анонимную функцию, заключив ее в список:

(defun double-property (symbol prop)
   (change-property symbol prop '(lambda (x) (* 2 x))))

В этом случае анонимная функция сохраняется как лямбда-выражение в скомпилированном коде. Байт-компилятор не может предположить, что этот список является функцией, даже если он выглядит как единица, поскольку он не знает, что change-propertyнамеревается использовать его как функцию.

Нарисовалась
источник
9

#'(aka function) может использоваться перед, (lambda ...)но он там избыточен, поэтому единственное место, где он действительно имеет значение, находится перед символом, как в #'car. В ELisp #'carи 'carпочти полностью эквивалентны, поэтому одной из основных целей является просто документировать намерение (т.е. указать тому, кто читает этот код, что вы намереваетесь использовать этот символ в качестве функции). Тем не менее, есть несколько обстоятельств, где разница более значительна:

  • Байт-компилятор использует преимущества этого документированного намерения, и когда вы пишете, #'carон проверит, carсуществует ли как функция, и если он не найдет ее, он выдаст предупреждение, так же, как если бы у вас был вызов этой функции. ,
  • Внутри cl-fletи cl-labels, только #'fможет ссылаться на локально определенную функцию f, потому что 'fвсе равно будет ссылаться на глобальный символ f(и какая функция может быть сохранена в своем symbol-functionслоте). Например

    (cl-flet ((car (x y) (+ x y)))
      (list #'car 'car))
    =>
    ((closure nil (x y) (+ x y)) car)
    
Стефан
источник