Khi nào / tại sao tôi nên sử dụng progn?


19

Tôi đã thấy prognđược sử dụng khá nhiều khi tôi duyệt các tệp cấu hình của người dùng Emacs có kinh nghiệm. Tôi tìm thấy lời giải thích tốt đẹp nàyprogn , nhưng điều tôi thực sự tò mò là, lợi ích của việc sử dụng chức năng này là gì? Lấy ví dụ đoạn trích này (lấy từ cấu hình của Sacha Chua ):

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

Có sự khác biệt lớn giữa cấu hình trên và điều này?

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t))

Tôi cảm thấy như ví dụ đầu tiên bằng cách nào đó sạch hơn, mặc dù nó có nhiều cú pháp hơn và trực giác của tôi là có thể có một số loại tăng hiệu suất từ ​​việc sử dụng progn, nhưng tôi không chắc chắn. Cảm ơn bạn cho bất kỳ hiểu biết!


7
Trong trường hợp cụ thể này, không có sự khác biệt: use-packagesẽ bao prognquanh một biểu mẫu: config của bạn nếu nó bị thiếu. Hãy thử: bạn có thể đặt điểm ở cuối a (use-package ...)và gọi M-x pp-macroexpand-last-sexpđể xem macro được mở rộng như thế nào. Bạn sẽ thấy rằng nó giống hệt nhau cho hai ví dụ này.
glucas

Một ví dụ progncần thiết: emacs.stackexchange.com/questions/39172/ Kẻ
npostavs

Câu trả lời:


11

prognthường được sử dụng khi xử lý các macro. Một số macro ( use-packagelà macro, tôi đã kiểm tra lần cuối) chỉ chấp nhận 1 biểu mẫu , trong đó các macro khác sử dụng tất cả các biểu mẫu còn lại .

progn được sử dụng trong trường hợp trước để biến một chuỗi các biểu mẫu thành một dạng duy nhất.

Trong ví dụ của bạn, cái đầu tiên sử dụng prognvà do đó có 1 mẫu sau :config. Trong lần thứ hai, có 3 hình thức . Nếu use-packagemacro chỉ mong đợi 1 hình thức sau :config, thì nó sẽ gây ra lỗi.

Điều đáng chú ý là việc sử dụng progncác tác phẩm trong cả hai trường hợp, trong khi bỏ qua nó chỉ hoạt động nếu macro chấp nhận nhiều hình thức. Do đó, một số người thích đơn giản là luôn luôn sử dụng progn, bởi vì nó sẽ luôn hoạt động.


15
Nó thực sự không có gì để làm với macro. Một số chức năng và macro có cái gọi là "ẩn progn", nghĩa là chúng chấp nhận bất kỳ số lượng giới tính nào dưới dạng đối số riêng biệt và đánh giá chúng theo trình tự. Những người khác thì không, và thay vào đó chỉ mong đợi / chỉ cho phép một đối số duy nhất mà bạn có thể muốn đánh giá nhiều giới tính theo trình tự. Đó là tất cả progn: nó cho phép bạn cung cấp một sexp mà khi được đánh giá sẽ đánh giá sexp progntheo thứ tự. So sánh (if true (progn a b c))với (when true a b c). Trong cả hai trường hợp, a, b, và cđược đánh giá theo thứ tự.
vẽ


4
Tôi không đồng ý rằng 99% các trường hợp sử dụng là cho các macro, vv Bất kỳ chức năng hoặc vĩ mô có thể được thông qua một prognsexp có chứa nhiều sexps đó được đánh giá cho tác dụng phụ của họ, trước khi trở về kết quả của người cuối cùng trong số này. Nó thực sự không có gì để làm với macro. Macro "như một ví dụ" là tốt. Tạo ấn tượng progntồn tại cho các macro và 99% sử dụng của nó là cho các macro, là sai lệch, IMO. prognlà về việc đưa một chuỗi các đánh giá vào một giới tính duy nhất (để phù hợp với một đối số dự kiến ​​nhất định), và do đó là về các tác dụng phụ .
vẽ

5
1. prognđã được giới thiệu trong Lisp 1.5 (xem phần Tính năng chương trình ), vào năm 1962, rất lâu trước khi các macro được thêm vào Lisp. Mục đích là để đánh giá tuần tự các biểu thức cho tác dụng phụ của chúng. 2. Xem progncách Emacs tự giới thiệu prognvới các lập trình viên Elisp. Xem zap-to-charmã cho một trường hợp sử dụng đơn giản.
vẽ

2
Chung ta co thể tỏ ra đông y để thể hiện chẳng đông y chut nao. Quan điểm của tôi là progngì cứ lí do gì để làm với các macro. Mục đích của nó tất nhiên là " truyền nhiều dạng dưới dạng một dạng " (từ của bạn) - cho dù là hàm hay macro hay dạng đặc biệt, nhưng cũng là " Eval BODY tạo thành tuần tự và trả về giá trị của dạng cuối " (chuỗi doc ). Bây giờ như mọi khi ("những ngày này", thực sự!). Một đánh giá có trật tự chỉ quan trọng đối với các tác dụng phụ, rõ ràng. Một trường hợp sử dụng nhất định (vĩ mô hoặc không) có thể hoặc không quan tâm đến thứ tự đánh giá, nhưng điều đó không liên quan. Và Emacs Lisp không phải là ngoại lệ theo bất kỳ cách nào trong vấn đề này.
vẽ

10

Lý do quan trọng nhất đối với progn được mô tả trong dòng đầu tiên của tài liệu progn (nhấn mạnh thêm):

progn là một hình thức đặc biệt làm cho mỗi đối số của nó được đánh giá theo trình tự và sau đó trả về giá trị của đối số cuối cùng.

Phụ lục:

Nếu không có progn , chuỗi không được bảo đảm, đặc biệt là nếu biểu thức tiếp theo phụ thuộc vào các tác dụng phụ hoặc các giá trị trở lại của biểu thức trước. progn thi hành trình tự thực hiện giống như trình tự văn bản. Giúp không nhầm lẫn thực hiện với phân tích cú pháp. Hành vi này quay trở lại các nguyên tắc cơ bản của cấu trúc điều khiển lisp và lập trình chức năng. Đây là một đoạn trích (nhấn mạnh thêm) từ hướng dẫn tham khảo lisp :

Các cấu trúc điều khiển tích hợp là các dạng đặc biệt do các biểu mẫu con của chúng không nhất thiết phải được đánh giá hoặc không được đánh giá tuần tự .

Liệu progn tăng hiệu suất?

Hiệu suất phân tích cú pháp, không. Hiệu suất thực hiện, không. Tốt nhất nó có thể bằng nhưng không bao giờ kỳ diệu tăng hiệu suất.

Khi nào progn được sử dụng ?

... Thường xuyên nhất là trong một thư giãn-bảo vệ, và, hoặc , trong phần sau đó của nếu .


Tôi không chắc tại sao điều đó lại quan trọng đến vậy. Emacs luôn đánh giá tuần tự.
lunaryorn

2
@lunaryorn xem câu trả lời cập nhật.
Người dùng Emacs

Tôi không chắc liệu tôi có hiểu bản chỉnh sửa của bạn hay không. Đương nhiên, có các hình thức đặc biệt với một thứ tự đánh giá khác nhau (ví dụ if), nhưng thứ tự đánh giá bình thường (ví dụ: hình thức cấp cao nhất, cơ quan chức năng, v.v.) là văn bản. Chắc chắn, ở một mức độ nào đó là một ẩn ý progn, nhưng đó thường không phải là những gì bạn sử dụng progn cho mã của riêng bạn.
lunaryorn

Tôi nghĩ rằng nút thủ công Elisp (elisp) Sequencingmà bạn liên kết nói lên tất cả.
Basil

10

Một cách tốt hơn để hiểu những gì prognlà bằng cách so sánh nó với gia đình: prog1prog2. Các nhoặc 1hoặc 2một phần của tên viết tắt của tuyên bố từ danh sách có kết quả mà bạn đang quan tâm. Nói cách khác, prognsẽ trả về kết quả của báo cáo kết quả cuối cùng nó chứa, trong khi đó prog1sẽ trở lại là người đầu tiên, và tương tự cho prog2.

Ngày nay, chức năng này có vẻ hơi khó xử vì chúng ta học cách mong đợi chương trình quay trở lại trong câu lệnh cuối cùng hoặc hướng dẫn nó một cách rõ ràng những gì sẽ trả về. Vì vậy prog1prog2rất hiếm khi được sử dụng. Tuy nhiên, nếu bạn nghĩ về nó, nó có ý nghĩa, và đây là cách:

Các ngôn ngữ lập trình khác nhau sử dụng các chiến lược khác nhau để mô tả ngữ nghĩa của chúng. Gia đình Lisp đã từng gắn chặt với ngữ nghĩa học. Không đi sâu vào chi tiết, loại ngữ nghĩa này gặp khó khăn đặc biệt với thứ mà chúng ta đã biết là "tuyên bố", không phải là "biểu thức". Ý nghĩa của mã thường được nghĩ theo các cách kết hợp chức năng, trong khi một "câu lệnh" thậm chí không thể được mô tả như là một hàm (vì nó không đánh giá được bất cứ điều gì) vì vậy rất khó đối phó. Tuy nhiên, vì Lisp cho phép các hiệu ứng phụ, đôi khi một lập trình viên muốn sử dụng một biểu thức mà không sử dụng giá trị của nó theo cách mà nó không ảnh hưởng đến biểu thức theo sau nó. Và đây là nơi progXgia đình đến.

Trong các ngôn ngữ giống như C, tính năng này đôi khi được gọi là điểm thứ tự (ví dụ ;,ví dụ). prognlà điều cần thiết cho các ngôn ngữ giống Lisp cũng như các ngôn ngữ giống như ;C. Đó là một tính năng cơ bản của ngôn ngữ mà người ta không thể dễ dàng thay thế. Tuy nhiên, không giống như trong các ngôn ngữ kiểu C, Lisp có xu hướng xây dựng trừu tượng cú pháp bằng cách ẩn hoàn toàn cú pháp của cấp độ thấp hơn. Và đây có lẽ là lý do tại sao bạn không thấy prognđược sử dụng thường xuyên, nhưng nó là một trong những khối xây dựng quan trọng, khi nói đến việc xây dựng trừu tượng ngôn ngữ cấp cao hơn (sa macro).

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.