2015-03-30 21 views
12

Nó là một kỹ thuật sử dụng thường xuyên trong On Lisp, mà là trên Common Lisp:Tại sao biểu thức lambda báo giá sắc nét?

> (mapcar #'(lambda (x) (+ x 10)) 
     '(1 2 3)) 
(11 12 13) 

Tại sao sắc nét-quote cần thiết hoặc thậm chí có thể? Các biểu thức lambda trả về các đối tượng hàm và trích dẫn sắc nét trả về các đối tượng hàm từ các tên. Tôi cũng đã nghe thông tin mâu thuẫn về việc liệu biểu thức lambda có phải là tên hay không - cụ thể là Trên Lisp mâu thuẫn với tiêu chuẩn, nhưng mã của anh ta dường như hoạt động mà cũng mâu thuẫn với tiêu chuẩn.

Trong elisp it seems it's not needed at all. Điều ngạc nhiên của tôi là không có thảo luận về phạm vi từ vựng, vì vậy không rõ tại sao nó lại khác với Common Lisp. Nhưng this answer nói rằng các biểu thức lambda không được trích dẫn không có ý nghĩa gì, do đó, trớ trêu thay, có thể giới thiệu các biểu thức lambda chưa được trích dẫn như là đường cú pháp cho các trích dẫn. Nhưng mâu thuẫn này là the elisp manual's claim rằng "Trong Emacs Lisp, một danh sách như vậy là một biểu thức hợp lệ để đánh giá một đối tượng hàm."

Câu hỏi này được gắn thẻ cả thông thường và e-lisp bởi vì tôi đang cố gắng hiểu mô hình lý thuyết cơ bản cả hai và tìm hiểu chúng bằng cách tìm hiểu sự khác biệt của chúng. (Thực tế hơn tôi đang cố gắng học elisp nhưng tìm thấy rất nhiều tài nguyên tốt trên Common Lisp nên tôi bắt kịp học cả hai).

+0

Xem thêm [sách hướng dẫn tham khảo Elisp] (https://www.gnu.org/software/emacs/manual/html_node/elisp/Anonymous-Functions.html#Anonymous-Functions) ngụ ý rằng 'hàm' trích dẫn sẽ giúp trình biên dịch byte xác định các đoạn mã cần được biên dịch. Nhưng tôi đồng ý rằng điều này có lẽ nên được giải thích chi tiết hơn bởi ai đó với cái nhìn sâu sắc thích hợp. – tripleee

Trả lời

6

Tóm lại, bạn không cần phải sắc nét-quote lambda vì nó là một macro mở rộng (function (lambda ...)), và nó là function mà làm tất cả sự kỳ diệu.

Ý nghĩa duy nhất trong đó function là không cần thiết là bạn không phải tự mình nhập. Đó là function, không phải là lambda, đó là toán tử cơ bản. Các biểu thức lambda chỉ là các danh sách bình thường (trong đó function biết cách biến thành các đối tượng hàm) và lambda chỉ là một macro thông thường. Vì vậy, bạn đã có những thứ khá ngược: biểu thức lambda trả về các đối tượng hàm không obviate functionlambda được giải thích về mặt sốfunction.

Một nếp nhăn bổ sung là trong Emacs Lisp, danh sách bắt đầu bằng lambda có thể được coi là các hàm trực tiếp, không qua function. Đây không phải là trường hợp trong CL (mặc dù một chuyển đổi rõ ràng có sẵn ở dạng (coerce some-list 'function)).

4

Tất cả đều phải làm với lịch sử. (lambda ...) chỉ là cú pháp đường cho #'(lambda ..). Các phiên bản trước của Common Lisp không có lambda được định nghĩa là macro. Ví dụ. nếu bạn đọc Peter Norvigs essay about Quines (PD, page2) mà bạn nhìn thấy ông tuyên bố rõ ràng bạn cần tạo vĩ mô như sau:

(defmacro lambda (args &body body) 
    "Allow (lambda (x) ...) instead of #’(lambda (x) ...)" 
    ‘#’(lambda ,args .,body)) 

Vì vậy khi viết (lambda ...) ngày nay một macro tiêu chuẩn ghi đè nó để #'(lambda ...).

On Lisp là một cuốn sách cũ và nó có thể đã được xuất bản lần đầu tiên trước khi macro trở thành tiêu chuẩn. Nó cũng có thể là Paul Graham được sử dụng để viết #'(lambda ...) và đã bị mắc kẹt với nó.

Tôi đã thấy rằng các ấn bản sau này của sách máy tính thường thay đổi ít nhất có thể khi tuân thủ một tiêu chuẩn mới hơn. Tôi không chắc đó là một điều tốt.

14

Lisp thường được giả định.

Tại sao cần phải có báo giá sắc nét hoặc thậm chí có thể?

Nếu bạn muốn tính toán một đối tượng chức năng từ một tên hàm (đặc biệt nếu bạn muốn đề cập đến một từ vựng ràng buộc) hoặc một biểu thức lambda, bạn cần các nhà điều hành đặc biệt FUNCTION, hoặc ngắn hơn #'.

biểu thức lambda trở lại đối tượng chức năng,

Họ không. Biểu thức Lambda thậm chí không thể được đánh giá.

Trong Lisp thông thường có vẻ như (lambda() nil) có thể được đánh giá. Nhưng nó không thể.

Thỉnh thoảng sau khi CLtL1 một macro LAMBDA đã được thêm vào để mở rộng nó thành biểu thức (FUNCTION ...). Macro này tiết kiệm một số đánh máy và chúng ta hãy mã trông giống như Scheme. Hãy kiểm tra LAMBDA macro này:

CL-USER 17 > (macroexpand-1 '(lambda()())) ; not a lambda expression 
(FUNCTION 
    (LAMBDA NIL NIL)       ; <- this is a lambda expression 
) 
T 

Điều này có nghĩa rằng những điều sau đây sẽ xảy ra nếu bạn đánh giá (lambda()()):

  • LAMBDA là một macro. Do đó, biểu mẫu được mở rộng thành (function (lambda()())).
  • (function (lambda()())) ->FUNCTION là một toán tử đặc biệt. Nó trả về một đối tượng hàm
  • ->

Nếu bạn viết: #'(lambda()()) hoặc (function (lambda()())), sau đó bạn sẽ bỏ qua việc mở rộng vĩ mô.

rồi, bây giờ cho một cái gì đó kỳ lạ:

CL-USER 18 > (lambda()()) ; <- this is not a lambda expression. 
           ; it's a macro form, see above 
#<anonymous interpreted function 40600009FC> 

Bởi vì ở trên là một hình thức vĩ mô, nó sẽ được mở rộng đầu tiên và sau đó nó có thể được đánh giá.

CL-USER 19 > (function   ; <- this is a special form 
       (lambda()()) ; <- this is a lambda expression 
      ) 
#<anonymous interpreted function 4060000C0C> 

Đây thực sự là biểu thức lambda. Bên trong toán tử đặc biệt FUNCTION biểu mẫu sẽ không được macro mở rộng hoặc tương tự.

CL-USER 20 > (     ; <- this is a function call 
       (lambda()()) ; <- this is a lambda expression 
      ) 

Trên một lần nữa, hiển thị biểu thức lambda. Trường hợp ((function (lambda()()))) không hợp lệ Common Lisp. Ở vị trí chức năng của một cuộc gọi hàm, Common Lisp dự kiến ​​hoặc là một tên hàm hoặc một biểu thức lambda, nhưng không phải là một cái gì đó cần được đánh giá.

và trả về trích dẫn sắc nét đối tượng chức năng từ tên.

FUNCTION, mà #' là một ký hiệu ngắn, trả về đối tượng chức năng từ tên hàm hay biểu thức lambda.

Xem tài liệu: FUNCTION.

Tôi cũng đã nghe thông tin trái ngược nhau về việc liệu các biểu thức lambda là những cái tên - đặc biệt On Lisp mâu thuẫn với tiêu chuẩn, nhưng mã của ông dường như làm việc mà còn mâu thuẫn với tiêu chuẩn.

Nếu bạn muốn nghe từ cuối cùng, hãy đọc tiêu chuẩn ANSI CL. Hoặc sử dụng Common Lisp Hyperspec, có thể đọc được trên web và được lấy từ tiêu chuẩn.

On Lisp chắc chắn là hữu ích để đọc, nhưng nó có thể không làm theo những chỉ dẫn hoặc ngữ nghĩa của ANSI CL đầy đủ chi tiết. Trên Lisp đã được xuất bản sau CLtL2, nhưng trước khi ANSI CL.

có nghĩa là gì thực tế khi viết mã?

Nếu bạn cũ, như tôi, và CLtL1 là điều cuối cùng bạn đọc của Common Lisp sau đó viết mã như:

(mapcar #'(lambda (x) (* x x)) '(1 2 3)) 

Nếu bạn thậm chí còn lớn hơn và lớn lên với Đề án, hoặc là trẻ và đã đọc Common Lisp Hyperspec, sau đó bạn có thể muốn viết:

(mapcar (lambda (x) (* x x)) '(1 2 3)) 

Nhưng đối với tất cả, khi nói đến hoạt động tên, đây là mặc định để viết:

(mapcar #'sin '(1 2 3)) 
1

Từ khóa function dường như có ý nghĩa khác nhau trong các ngôn ngữ Lisp khác nhau.

Trong LISP 1.5, nó được sử dụng để tạo đóng cửa, sử dụng thiết bị funarg. Tham chiếu: http://c2.com/cgi/wiki?DynamicClosure và Hướng dẫn lập trình LISP 1.5, Phụ lục B.

Trong MacLisp, nó được sử dụng như một gợi ý cho trình biên dịch nói rằng biểu thức lambda có thể được biên dịch thành mã. Tham chiếu: The Pitmanual, 7. Definitional Forms. Nó không được sử dụng để tạo bao đóng; các hình thức đặc biệt *function đã làm một cái gì đó tương tự. Tham khảo The Pitmanual, 3. The Evaluator.

Trong Emacs Lisp, đó là gợi ý cho trình biên dịch và cũng có thể tạo các đóng cửa từ vựng. Tham chiếu: Emacs Lisp Reference Manual, 12.7 Anonymous Functions.

Các vấn đề liên quan