Kiedy należy stosować ostre cytaty?

10

Widzę ostre cytaty używane w kodzie eLisp innych ludzi i używam ich osobiście, ale nie jestem całkowicie pewien, kiedy są odpowiednie, a kiedy nie.

Czy ktoś mógłby wyjaśnić, kiedy właściwe jest stosowanie ostrych cytatów i kiedy zamiast tego należy stosować zwykłe pojedyncze cytaty?

izkon
źródło
3
Uwaga Istnieje wiele duplikatów tego pytania tutaj lub w SO
Filip
Możliwy duplikat Kiedy precyzyjnie zacytować wyrażenie lambda?
Andrew Swann,
1
Nie sądzę, żeby to był duplikat: emacs.stackexchange.com/questions/3595 dotyczy używania #'lambda (gdzie odpowiedź jest w zasadzie „nigdy”), podczas gdy pytanie @ izkon dotyczy raczej #'zastosowania symboli.
Stefan

Odpowiedzi:

12

#'jest po prostu skrótem function, tak jak 'jest skrótem dla quote.

Możesz go użyć w dowolnym miejscu, w którym chcesz wskazać kompilatorowi bajtów, interpreterowi lub czytelnikowi, że jego argument ma być (jest traktowany) funkcją.

W wielu kontekstach kontekst określa sposób traktowania argumentu, jeśli na przykład po prostu go zacytujesz (użyj quotelub ') zamiast używać #'(lub function). Na przykład w kontekście, w którym symbol jest używany tylko ze względu na jego symbol-functionwłaściwość, tj. Jest używany jako funkcja, możesz po prostu przekazać symbol (np. Przez zacytowanie go lub przekazanie zmiennej, której wartością jest symbol).

Ale czasami kod jest wyraźniejszy, jeśli używasz go #'w takich kontekstach. Nawet jeśli sam Emacs-Lisp rozumie, że symbol jest używany jako funkcja w takich kontekstach, może to pomóc w podkreśleniu tego dla ludzkiego czytelnika kodu.

W niektórych innych Lisps, traktowanie form lambda, które są po prostu cytowane (z ') lub nie są cytowane, może różnić się od ich użycia w pozycji funkcyjnej, gdy jest cytowany za pomocą function( #'). Ale nie w Emacs Lisp. W Emacs Lisp nie musisz zacytować (za pomocą albo 'i #') formularz lambda, które mają być traktowane jako funkcja (a nie po prostu jako listę). Jeśli chcesz, aby była traktowana jak lista, z samochodem lambdaitp., To zacytuj ją (z ') - ilustruje to poniższy przykład.

Od (elisp) Funkcje anonimowe :

- Formularz specjalny: function function-object

Ten specjalny formularz powraca FUNCTION-OBJECTbez jego oceny.

Pod tym względem jest podobny do quote(* notatka Cytowanie: :). Ale w przeciwieństwie do tego quote, służy również jako uwaga dla ewaluatora Emacsa i kompilatora bajtów, który FUNCTION-OBJECTma być używany jako funkcja. Zakładając, że FUNCTION-OBJECTjest poprawnym wyrażeniem lambda, ma to dwa skutki:

• Gdy kod jest skompilowany bajtowo, FUNCTION-OBJECTjest kompilowany w obiekt funkcji bajt-kod (* uwaga Kompilacja bajtów: :).

• Gdy włączone jest powiązanie leksykalne, FUNCTION-OBJECTjest konwertowane na zamknięcie. * Uwaga Zamknięcia ::.

Składnia odczytu #'jest skrótem do użycia function. Następujące formularze są równoważne:

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

W poniższym przykładzie definiujemy change-propertyfunkcję, która przyjmuje funkcję jako trzeci argument, a następnie double-property funkcję, która korzysta z change-propertyniej, przekazując jej funkcję anonimową:

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

Pamiętaj, że nie podajemy lambdaformularza.

Jeśli skompilujesz powyższy kod, anonimowa funkcja również zostanie skompilowana. Nie stanie się tak, jeśli, powiedzmy, skonstruowałeś funkcję anonimową, cytując ją jako listę:

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

W takim przypadku anonimowa funkcja jest przechowywana jako wyrażenie lambda w skompilowanym kodzie. Kompilator bajtów nie może założyć, że ta lista jest funkcją, chociaż wygląda jak jedna, ponieważ nie wie, że change-propertyzamierza użyć jej jako funkcji.

Rysował
źródło
9

#'(aka function) może być używane przed, (lambda ...)ale jest tam zbędne, więc jedynym miejscem, w którym ma to naprawdę znaczenie, jest symbol, jak w #'car. W ELisp #'cari 'carsą prawie całkowicie równoważne, więc jednym z głównych celów jest po prostu udokumentowanie zamiaru (tj. Wskazanie każdemu, kto czyta ten kod, że zamierzasz użyć tego symbolu jako funkcji). Istnieje jednak kilka okoliczności, w których różnica jest bardziej znacząca:

  • Kompilator bajtów korzysta z tej udokumentowanej intencji, a gdy napiszesz #'car, sprawdzi, czy caristnieje jako funkcja, a jeśli go nie znajdzie, wyemituje ostrzeżenie, tak jak w przypadku wywołania tej funkcji .
  • Wewnątrz cl-fleti cl-labels, #'fmoże odnosić się tylko do funkcji zdefiniowanej lokalnie f, ponieważ 'fnadal będzie odnosić się do symbolu globalnego f(i dowolnej funkcji, która może być zapisana w jej symbol-functiongnieździe). Na przykład

    (cl-flet ((car (x y) (+ x y)))
      (list #'car 'car))
    =>
    ((closure nil (x y) (+ x y)) car)
    
Stefan
źródło