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)
function
là ở vị trí chức năng (sau dấu ngoặc đơn mở) và variable
khô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-variable
bị ràng buộc như một biến" chứ không phải "là biểu tượng my-variable
bị ràng buộc như một biến.
Vậy tại sao lại bound-and-truep
cư 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-p
hì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ề nil
nếu my-variable
không boundp
hoặ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 quote
là 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-p
cũng là một macro đọc. Nếu nó trích dẫn một biểu tượng như trong `symbol
nó 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-p
một macro trong khi boundp
khô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-p
có 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 '
.
setq
viết tắt củaset 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ó (setq
là một ngoại lệ chính).