Làm thế nào để biết khi nào hoặc khi nào không sử dụng dấu ngoặc đơn trước tên biến?


31

Tôi có những điều dưới đây:

(setq some-variable "less")

Tôi bối rối tại sao tôi phải sử dụng trích dẫn duy nhất với boundpnhưng không với bound-and-true-p.

Ví dụ 1:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))

Kết quả:

"một số biến là ít"

Ví dụ 2a:

(when (bound-and-true-p some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Kết quả:

"một số biến là ít"

Ví dụ 2b:

(when (bound-and-true-p 'some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Kết quả:

và: Đối số kiểu sai: ký hiệu, (trích dẫn một số biến)


5
Điều đáng nói là setqviết tắt của set quoted, và ban đầu là một macro được mở rộng thành (set 'some-variable "less"). Nói chung, Elisp không nhất quán khủng khiếp về các đối số được trích dẫn so với không được trích dẫn, nhưng bất kỳ hàm nào (không phải macro) cần tương tác với một biến thay vì giá trị sẽ lấy tham số của nó ( setqlà một ngoại lệ chính).
shosti

2
FWIW, bound-and-true-plà một macro ngu ngốc. Hay đúng hơn, tên của nó là ngu ngốc. 99,99% thời gian khi bạn muốn làm (and (boundp 'FOO) FOO)bạn sử dụngFOO nó để sử dụng giá trị của . Bạn không làm điều đó chỉ để có được một giá trị thật. (1) Macro không cần thiết - mã mà nó thay thế là tầm thường và nhỏ. (2) Tên này gây hiểu nhầm - đó là về giá trị biến, không chỉ kiểm tra xem giá trị biến có hay không nil.
vẽ

Câu trả lời:


24

Câu trả lời ngắn

Nếu bạn đang cố gắng sử dụng chính biến đó, thì hãy sử dụng 'some-variable. Nếu bạn đang cố gắng sử dụng giá trị được lưu trữ trong biến, hãy sử dụng some-variable.

  • ràng buộc sử dụng biểu tượng để nó sẽ xem xét bất cứ điều gì có thể bị ràng buộc, bao gồm các chức năng. Nó chỉ quan tâm xem có một biểu tượng phù hợp, không phải giá trị là gì.
  • ràng buộc và truep sử dụng var và trả về giá trị. Trong trường hợp này, bạn cần cung cấp giá trị của biểu tượng cho hàm. Nếu không có ký hiệu var nào bị ràng buộc, hoặc giá trị là 0 thì nó sẽ trả về nil.

Giải trình

Đối với định nghĩa thủ công xin vui lòng xem hướng dẫn .

'(quote ...)cả hai thực hiện cùng một mục đích trong emacs-lisp.

Mục đích của việc này là để vượt qua hình thức không được đánh giá cho môi trường xung quanh hơn là đánh giá nó.

Trong ví dụ của bạn, giả sử chúng tôi có mức cao hơn sau

(setq some-variable "less") ;; Rather than just 't for clarity

Sau đó, việc đánh giá diễn ra như sau:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))
;; ==> (boundp 'some-variable) ; 't
;; ==> some-variable is "less"

Trong khi không có trích dẫn:

(when (boundp some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))
;; ==> (boundp "less") ; "less" is not a variable. -> Error

Lisp đánh giá các biểu mẫu khi chúng đạt được, bằng cách trích dẫn biểu mẫu bạn ngăn đánh giá để biến thực tế (hoặc danh sách hoặc tên hàm) được thông qua.


Cảm ơn! Câu trả lời của bạn khiến tôi nhảy vào nguồn của cả hai và giúp tôi đưa ra giải pháp. Tôi cũng cập nhật câu hỏi của tôi với các ví dụ rõ ràng.
Kaushal Modi

6
Tôi rất vui vì điều này đã giúp các op, nhưng nó không thực sự trả lời câu hỏi (theo cách hữu ích cho những người khác có cùng câu hỏi). Bạn chỉ giải thích rằng các biểu tượng phải được trích dẫn nếu không chúng được đánh giá. Bạn không giải thích tại sao đó không phải là trường hợp bound-and-truepvà câu hỏi là tại sao tôi phải trích dẫn khi sử dụng boundpmà không phải khi sử dụng bound-and-truep.
tarsius

@tarsius Tôi thực sự bao gồm sự phân biệt giữa boundpyêu cầu một biểu tượng (không đánh giá) và bound-and-truepcần giá trị của biến trong các dấu đầu dòng (được chỉnh sửa sau câu trả lời ban đầu)
Jonathan Leech-Pepin

Tôi nghĩ rằng điều cần thiết là phải đề cập đến lý do tại sao lại như vậy (macro có thể chọn không đánh giá) thay vì chỉ đề cập rằng chuỗi doc nói như vậy. Tôi nghĩ rằng đây là một câu hỏi rất hay và ràng buộc so với ràng buộc và đúng-p chỉ là một ví dụ. Điều mà câu hỏi thực sự sôi nổi là mong muốn tìm hiểu về các quy tắc đánh giá.
tarsius

@tarsius Không đánh giá các quy tắc được giải thích bởi câu trả lời này? Ít nhất là những câu hỏi cơ bản chỉ liên quan đến trích dẫn ... Câu trả lời của bạn chắc chắn đầy đủ hơn, nhưng nó vượt xa chủ đề, phải không?
T. Verron

16

Một biểu tượng ở vị trí không có chức năng được coi là tên của một biến. Trong (function variable) functionlà ở vị trí chức năng (sau dấu ngoặc đơn mở) và variablekhông. Trừ khi các biến được trích dẫn rõ ràng được thay thế bằng các giá trị của chúng.

Nếu bạn đã viết (boundp my-variable)điều đó có nghĩa là "là biểu tượng được lưu trữ trong giá trị của biến my-variablebị ràng buộc như một biến" chứ không phải "là biểu tượng my-variablebị ràng buộc như một biến.

Vậy tại sao lại bound-and-truepcư xử khác nhau?

Đây là một macro và các quy tắc đánh giá (chức năng) thông thường không áp dụng ở đây, các macro được tự do quyết định xem và khi nào các đối số của chúng được đánh giá. Những gì macro thực sự làm là bằng cách nào đó biến đổi các đối số và trả về kết quả dưới dạng một danh sách, sau đó được đánh giá. Việc chuyển đổi và đánh giá cuối cùng xảy ra ở các thời điểm khác nhau, được gọi là thời gian mở rộng vĩ mô và thời gian đánh giá.

Đây là định nghĩa của bound-and-true-phình như:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

Điều này sử dụng các macro đọc khác với các macro lisp (nhiều hơn ở bên dưới). Để không làm phức tạp thêm điều này, cho phép không sử dụng bất kỳ macro người đọc nào:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  (list 'and (list 'boundp (list 'quote var)) var))

Nếu bạn viết

(bound-and-true-p my-variable)

đó là lần đầu tiên "dịch" sang

(and (boundp 'my-variable) my-variable)

và sau đó được đánh giá trả về nilnếu my-variablekhông boundphoặc giá trị của my-variable(tất nhiên cũng có thể là nil).


Bạn có thể nhận thấy rằng bản mở rộng không

(and (boundp (quote my-variable)) my-variable)

như chúng ta có thể mong đợi quotelà một hình thức đặc biệt, không phải là một macro hoặc chức năng. Giống như macro, các hình thức đặc biệt có thể làm bất cứ điều gì với đối số của chúng. Hình thức đặc biệt này chỉ đơn giản trả về đối số của nó, ở đây là một biểu tượng, thay vì giá trị biến của biểu tượng. Đó thực sự là mục đích duy nhất của hình thức đặc biệt này: ngăn chặn đánh giá! Macro không thể tự làm điều đó, chúng cần sử dụng quoteđể làm như vậy.

Vì vậy, những gì với '? Nó là một macro người đọc , như đã đề cập ở trên không giống như một macro không thể thiếu . Trong khi các macro được sử dụng để chuyển đổi mã / dữ liệu, các macro đọc được sử dụng trước đó khi đọc văn bản để chuyển đổi văn bản đó thành mã / dữ liệu.

'something

là một hình thức ngắn cho

(quote something)

`được sử dụng trong định nghĩa thực tế bound-and-true-pcũng là một macro đọc. Nếu nó trích dẫn một biểu tượng như trong `symbolnó tương đương với 'symbol, nhưng khi được sử dụng để trích dẫn một danh sách như trong `(foo bar ,baz)nó hoạt động khác nhau trong các hình thức có tiền tố ,được đánh giá.

`(constant ,variable)

tương đương với

(list (quote constant) variable))

Điều này sẽ trả lời câu hỏi tại sao các biểu tượng không trích dẫn đôi khi được đánh giá (thay thế bằng các giá trị của chúng) và đôi khi không; macro có thể sử dụng quoteđể ngăn chặn một biểu tượng được đánh giá.

Nhưng tại sao bound-and-true-pmột macro trong khi boundpkhông? Chúng ta phải có thể xác định xem các ký hiệu tùy ý, không được biết đến cho đến thời gian chạy, có bị ràng buộc như các ký hiệu không. Điều này sẽ không thể xảy ra nếu boundpđối số được tự động trích dẫn.

bound-and-true-pđược sử dụng để xác định xem một biến đã biết có được xác định hay không và nếu có thì sử dụng giá trị của nó. Điều này hữu ích nếu thư viện có phụ thuộc tùy chọn vào thư viện bên thứ ba như trong:

(defun foo-get-value ()
  (or (bound-and-true-p bar-value)
      ;; we have to calculate the value ourselves
      (our own inefficient or otherwise undesirable variant)))

bound-and-true-pcó thể được định nghĩa là một hàm và yêu cầu trích dẫn đối số nhưng vì nó được dành cho các trường hợp bạn biết trả trước biến nào bạn quan tâm về một macro đã được sử dụng để cứu bạn khỏi phải nhập '.


Thật đáng ngạc nhiên cũng trả lời.
Charles Ritchie

2

Từ mã nguồn của boundp:

DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
      doc: /* Return t if SYMBOL's value is not void.
Note that if `lexical-binding' is in effect, this refers to the
global value outside of any lexical scope.  */)

boundpmong đợi symbolnhư là đầu vào. 'some-variablelà một biểu tượng cho biến some-variable.

Từ mã nguồn của bound-and-true-p:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

bound-and-true-pmong đợi variablenhư là đầu vào.

Trong bound-and-true-pmacro, nó có được biểu tượng bằng cách làm (quote ,var). Vì vậy, nếu đầu vào là some-variable, (quote ,var)sẽ có kết quả 'some-variable.

Nhưng khi tôi cung cấp cho các đầu vào 'some-variableđể bound-and-true-p, tôi nhận được lỗi: and: Wrong type argument: symbolp, (quote some-variable)vì vĩ mô là không chờ đợi một biểu tượng ( 'some-variable) tại đầu vào.


Chỉ cần một cái đầu lên. ''symbol không có ý nghĩa Nó có nghĩa là (quote (quote symbol)). Lý do bạn gặp lỗi là vì đó không phải là một đối số hợp lệ boundp.
Malabarba

@Malabarba Cảm ơn. Tôi đã thực hiện điều chỉnh.
Kaushal Modi
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.