Quando citações nítidas devem ser usadas?

9

Vejo citações nítidas sendo usadas no código eLisp de outras pessoas e as utilizo pessoalmente, mas não sou totalmente claro quando elas são apropriadas e quando não são.

Alguém poderia esclarecer exatamente quando é apropriado usar aspas nítidas e quando aspas simples comuns devem ser usadas?

izkon
fonte
3
nb Há muitas duplicatas para esta pergunta aqui ou no SO
phils
Possível duplicata de Quando citar nitidamente uma expressão lambda?
Andrew Swann
11
Não acho que seja uma duplicata: emacs.stackexchange.com/questions/3595 é sobre o uso #'com lambda (onde a resposta é basicamente "nunca"), enquanto a pergunta do @izkon se aplica mais ao uso de #'símbolos aplicados.
22817 Stefan #

Respostas:

11

#'é apenas uma abreviação para function, assim como 'é uma abreviação para quote.

Você pode usá-lo em qualquer lugar onde queira indicar ao compilador de bytes ou ao intérprete ou a um leitor humano que seu argumento deve ser (é tratado como) uma função.

Em muitos contextos, o contexto determina como o argumento é tratado se, por exemplo, você simplesmente o citar (use quoteou ') em vez de usar #'(ou function). Por exemplo, em um contexto em que um símbolo é usado apenas para sua symbol-functionpropriedade, ou seja, é usado como uma função, você pode simplesmente passar o símbolo (por exemplo, citando-o ou passando uma variável cujo valor é o símbolo).

Mas, às vezes, o código é mais claro se você usar #'em tais contextos. Mesmo que o próprio Emacs-Lisp entenda que o símbolo é usado como uma função em tais contextos, isso pode ajudar a enfatizar isso para um leitor humano do código.

Em alguns outros Lisps, o tratamento de formulários lambda que são simplesmente citados (com ') ou não citados pode diferir do uso em uma posição de função quando citados usando function( #'). Mas não no Emacs Lisp. No Emacs Lisp, você não precisa citar (usando um 'ou #') um formulário lambda que deseja tratar como uma função (e não simplesmente como uma lista). Se você deseja que ele seja tratado apenas como uma lista, com carro lambda, etc., cite-o (com ') - o exemplo abaixo ilustra isso.

Funções anônimas do (elisp) :

- Formulário especial: function function-object

Este formulário especial retorna FUNCTION-OBJECTsem avaliá-lo.

Nisso, é semelhante a quote(* note Quoting: :). Mas quote, diferentemente , também serve como uma nota para o avaliador do Emacs e o compilador de bytes que FUNCTION-OBJECTse destina a ser usado como uma função. Supondo que FUNCTION-OBJECTseja uma expressão lambda válida, isso tem dois efeitos:

• Quando o código é FUNCTION-OBJECTcompilado em bytes , ele é compilado em um objeto de função de código de bytes (* note Compilação de bytes: :).

• Quando a ligação lexical está ativada, FUNCTION-OBJECTé convertida em um fechamento. * Nota Encerramentos ::.

A sintaxe de leitura #'é um atalho para uso function. Os seguintes formulários são todos equivalentes:

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

No exemplo a seguir, definimos uma change-propertyfunção que aceita uma função como seu terceiro argumento, seguida por uma double-property função que faz uso change-propertydela passando uma função anônima:

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

Observe que não citamos o lambdaformulário.

Se você compilar o código acima, a função anônima também será compilada. Isso não aconteceria se, digamos, você tivesse construído a função anônima, citando-a como uma lista:

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

Nesse caso, a função anônima é mantida como uma expressão lambda no código compilado. O compilador de bytes não pode assumir que esta lista seja uma função, mesmo que pareça uma, pois não sabe que change-propertypretende usá-la como uma função.

Desenhou
fonte
9

#'(aka function) pode ser usado na frente, (lambda ...)mas é redundante, então o único lugar em que é realmente significativo está na frente de um símbolo, como em #'car. No ELisp, #'care 'carsão quase completamente equivalentes, um dos principais objetivos é simplesmente documentar a intenção (ou seja, indicar para quem lê esse código que você pretende usar esse símbolo como uma função). No entanto, existem algumas circunstâncias em que a diferença é mais significativa:

  • O compilador de bytes aproveita essa intenção documentada e, quando você escreve #'car, verifica se carexiste como uma função e, se não a encontrar, emitirá um aviso, como faria se você tivesse uma chamada para essa função. .
  • Inside cl-flete cl-labels, só #'fpode se referir à função definida localmente f, porque 'fainda se refere ao símbolo global f(e a função que estiver armazenada em seu symbol-functionslot). Por exemplo

    (cl-flet ((car (x y) (+ x y)))
      (list #'car 'car))
    =>
    ((closure nil (x y) (+ x y)) car)
    
Stefan
fonte