Khi nào nên trích dẫn sắc nét?


9

Tôi thấy các trích dẫn sắc nét đang được sử dụng trong mã eLisp của người khác và tôi tự sử dụng chúng, nhưng tôi không hoàn toàn rõ ràng khi nào chúng phù hợp và khi nào thì không.

Bất cứ ai cũng có thể làm rõ chính xác khi nào thì thích hợp để sử dụng dấu ngoặc kép và khi nào nên sử dụng dấu ngoặc đơn thông thường?


3
nb Có nhiều bản sao cho câu hỏi này tại đây hoặc trên SO
phils


1
Tôi không nghĩ đó là một bản sao: emacs.stackexchange.com/questions/3595 là về việc sử dụng #'với lambda (trong đó câu trả lời về cơ bản là "không bao giờ"), trong khi câu hỏi của @ izkon áp dụng thay cho việc sử dụng các #'biểu tượng.
Stefan

Câu trả lời:


11

#'chỉ là tốc ký cho function, cũng như tốc 'quote.

Bạn có thể sử dụng nó ở bất cứ nơi nào bạn muốn chỉ ra cho trình biên dịch byte hoặc trình thông dịch hoặc trình đọc của con người rằng đối số của nó được dự kiến ​​là (được coi là) một hàm.

Trong nhiều bối cảnh, bối cảnh xác định cách đối số được xử lý nếu, ví dụ, bạn chỉ cần trích dẫn nó (sử dụng quotehoặc ') thay vì sử dụng #'(hoặc function). Ví dụ, trong ngữ cảnh chỉ sử dụng một ký hiệu cho thuộc tính của nó symbol-function, nghĩa là nó được sử dụng như một hàm, bạn chỉ có thể truyền ký hiệu (ví dụ: bằng cách trích dẫn nó hoặc truyền một biến có giá trị là ký hiệu).

Nhưng đôi khi mã sẽ rõ ràng hơn nếu bạn sử dụng #'trong các bối cảnh như vậy. Ngay cả khi chính Emacs-Lisp hiểu rằng biểu tượng được sử dụng như một hàm trong các bối cảnh như vậy, nó có thể giúp nhấn mạnh điều này cho người đọc mã của con người.

Trong một số Lisps khác, việc xử lý các dạng lambda được trích dẫn đơn giản (với ') hoặc không được trích dẫn có thể khác với việc sử dụng chúng ở vị trí hàm khi được trích dẫn bằng cách sử dụng function( #'). Nhưng không phải trong Emacs Lisp. Trong Emacs Lisp, bạn không cần trích dẫn (sử dụng 'hoặc #') một biểu mẫu lambda mà bạn muốn được coi là một hàm (và không chỉ đơn giản là một danh sách). Nếu bạn muốn nó được xử lý như một danh sách, với xe hơi lambda, v.v., thì hãy trích dẫn nó (với ') - ví dụ dưới đây minh họa điều này.

Từ (elisp) Hàm ẩn danh :

- Mẫu đặc biệt: function function-object

Hình thức đặc biệt này trả về FUNCTION-OBJECTmà không đánh giá nó.

Trong đó, nó tương tự như quote(* chú thích Trích dẫn: :). Nhưng không giống như quote, nó cũng đóng vai trò là một ghi chú cho trình đánh giá Emacs và trình biên dịch byte FUNCTION-OBJECTđược dự định sẽ được sử dụng như một hàm. Giả sử FUNCTION-OBJECTlà một biểu thức lambda hợp lệ, điều này có hai tác dụng:

• Khi mã được biên dịch byte, FUNCTION-OBJECTđược biên dịch thành đối tượng hàm mã byte (* lưu ý Byte Compilation: :).

• Khi liên kết từ vựng được bật, FUNCTION-OBJECTđược chuyển thành đóng. * Lưu ý Đóng ::.

Cú pháp đọc #'là một tay ngắn để sử dụng function. Các hình thức sau đây đều tương đương:

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

Trong ví dụ sau, chúng tôi định nghĩa một change-propertyhàm lấy một hàm làm đối số thứ ba của nó, theo sau là một double-property hàm sử dụng change-propertybằng cách chuyển cho nó một hàm ẩn danh:

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

Lưu ý rằng chúng tôi không trích dẫn lambdamẫu.

Nếu bạn biên dịch mã trên, hàm ẩn danh cũng được biên dịch. Điều này sẽ không xảy ra nếu, giả sử, bạn đã xây dựng hàm ẩn danh bằng cách trích dẫn nó dưới dạng danh sách:

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

Trong trường hợp đó, hàm ẩn danh được giữ dưới dạng biểu thức lambda trong mã được biên dịch. Trình biên dịch byte không thể coi danh sách này là một hàm, mặc dù nó trông giống như một hàm, vì nó không biết rằng nó change-propertycó ý định sử dụng nó như là một hàm.


9

#'(aka function) có thể được sử dụng ở phía trước (lambda ...)nhưng nó dư thừa ở đó, vì vậy nơi duy nhất thực sự có ý nghĩa là ở phía trước một biểu tượng, như trong #'car. Trong ELisp, #'car'cargần như hoàn toàn tương đương, vì vậy một trong những mục đích chính chỉ đơn giản là ghi lại ý định (nghĩa là chỉ ra cho bất kỳ ai đọc mã này mà bạn dự định sử dụng biểu tượng này làm chức năng). Tuy nhiên, có một vài trường hợp, trong đó sự khác biệt có ý nghĩa hơn:

  • Trình biên dịch byte tận dụng ý định được ghi lại này và khi bạn viết #'carnó sẽ kiểm tra xem có cartồn tại như một hàm hay không và nếu nó không tìm thấy nó, nó sẽ phát ra một cảnh báo, giống như nếu bạn có lệnh gọi đến hàm đó .
  • Bên trong cl-fletcl-labels, chỉ #'fcó thể đề cập đến chức năng được xác định cục bộ f, bởi vì 'fvẫn sẽ đề cập đến biểu tượng toàn cầu f(và bất kỳ chức năng nào có thể được lưu trữ trong symbol-functionkhe của nó ). Ví dụ

    (cl-flet ((car (x y) (+ x y)))
      (list #'car 'car))
    =>
    ((closure nil (x y) (+ x y)) car)
    
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.