2011-01-21 15 views
6

Tôi đã thấy một câu trả lời của How does Lisp let you redefine the language itself? Stack Overflow hỏi (trả lời bằng cách Noah Lavine):Có các macro biến đổi toàn bộ chương trình trong Lisp hoặc Lược đồ không?

Macro là không hoàn toàn một định nghĩa đầy đủ về ngôn ngữ, ít nhất là như xa như tôi biết (tôi' m thực sự là một Schemer, tôi có thể sai), bởi vì có một hạn chế. Macro chỉ có thể lấy một mã con duy nhất của mã của bạn và tạo một cây con duy nhất để thay thế nó. Vì vậy, bạn không thể viết các macro toàn bộ chương trình chuyển đổi, như là mát mẻ như vậy sẽ được.

Sau khi đọc, tôi tò mò muốn biết có "macro toàn bộ chương trình chuyển đổi" trong Lisp hoặc lược đồ (hoặc một số ngôn ngữ khác) hay không.

Nếu không thì tại sao?

  • Nó không hữu ích và không bao giờ yêu cầu?
  • Điều tương tự có thể đạt được bằng một số cách khác?
  • Không thể triển khai ngay cả trong Lisp?
  • Có thể, nhưng chưa được thử hoặc triển khai chưa?

Cập nhật

Một loại trường hợp sử dụng ví dụ

Như trong mã stumpwm đây là một số chức năng tất cả trong file nguồn lisp khác nhau sử dụng một động/toàn cầu defvar biến * màn hình-list * được xác định trong primitives.lisp, nhưng được sử dụng trong màn hình. lisp, user.lisp, window.lisp. (Ở đây mỗi file có chức năng, lớp, VAR liên quan đến một khía cạnh hoặc đối tượng)

Bây giờ tôi muốn xác định các chức năng theo việc đóng cửa nơi * màn hình-list * biến sẵn bằng hình thức let, nó không nên là biến động/toàn cục, nhưng không di chuyển tất cả các chức năng này vào một nơi (vì tôi không muốn các chức năng này bị mất từ ​​tập tin liên quan ) Do đó biến này sẽ chỉ có thể truy cập được vào các chức năng này.

Phía trên ví dụ: áp dụng như nhau cho nhãn và flet, do đó, nó sẽ tiếp tục có thể mà chúng tôi có thể làm cho nó như thế chỉ cần thay đổi, chức năng sẽ có sẵn, cho những người yêu cầu nó.

Lưu ý một cách có thể là triển khai và sử dụng một số macro defun_with_context để xác định nơi đối số đầu tiên là ngữ cảnh cho phép, biến flet xác định. Nhưng ngoài nó có thể đạt được bằng đầu đọc vĩ mô là Vatine và Gareth Rees trả lời.

Trả lời

5

Bạn trích dẫn Noah Lavine nói:

Một vĩ mô chỉ có thể đưa một cây con duy nhất của mã của bạn, và tạo ra một cây con duy nhất để thay thế nó

Đây là trường hợp cho các macro bình thường , nhưng macro đọc có quyền truy cập vào luồng đầu vào và có thể làm bất cứ điều gì họ thích với nó.

Xem Hyperspec section 2.2 và chức năng set-macro-character.

0

Luôn có lựa chọn sử dụng macro trình biên dịch (chúng có thể thực hiện chuyển đổi toàn bộ hàm dựa trên tiêu chí ít, nhưng không nên thay đổi giá trị trả về, vì điều đó sẽ gây nhầm lẫn).

Có các macro đọc, chúng biến đổi đầu vào "khi được đọc" (hoặc "trước khi đọc", nếu bạn thích). Tôi đã không thực hiện nhiều phần mềm đọc macro-quy mô lớn, nhưng tôi đã viết một số mã để cho phép các phần mềm cần đọc (thường đọc) trong Common Lisp, với một vài sự khác biệt tinh tế trong đường cú pháp giữa hai.

1

Cách tiếp cận điển hình là viết hệ thống mô-đun của riêng bạn. Nếu bạn chỉ muốn truy cập vào tất cả các mã, bạn có thể có một số loại tập tin nguồn mở rộng bộ xử lý trước hoặc bộ đọc kèm theo chú thích mô-đun của riêng bạn. Nếu sau đó bạn viết mẫu require hoặc import của riêng mình, cuối cùng bạn sẽ có thể thấy tất cả các mã trong phạm vi.

Để bắt đầu, bạn có thể viết biểu mẫu module của riêng bạn cho phép bạn xác định một số chức năng mà sau đó bạn biên dịch một cách thông minh trước khi phát ra mã được tối ưu hóa.

1

Tắt đầu của tôi, một vài cách tiếp cận:

Trước tiên, bạn có thể. Norvig points out rằng:

Chúng tôi có thể viết trình biên dịch làm bộ macro.

để bạn có thể chuyển đổi toàn bộ chương trình, nếu muốn. Tôi chỉ nhìn thấy nó được thực hiện hiếm khi, bởi vì thường là giao điểm giữa "những thứ bạn muốn làm cho mọi phần của chương trình" và "những thứ bạn cần macro/AST-type transformations" là một tập khá nhỏ. Một ví dụ là Parenscript, biến đổi mã Lisp của bạn ("một tập con mở rộng của CL") thành Javascript. Tôi đã sử dụng nó để biên dịch toàn bộ các tập tin của mã Lisp vào Javascript được phục vụ trực tiếp cho khách hàng web. Nó không phải là môi trường yêu thích của tôi, nhưng nó làm những gì nó quảng cáo.

Một tính năng có liên quan là "lời khuyên", mà Yegge describes as: hệ thống

vĩ đại cũng có lời khuyên. Không có tên được chấp nhận rộng rãi cho tính năng này. Đôi khi nó được gọi là móc, hoặc bộ lọc, hoặc lập trình hướng-khía cạnh. Theo như tôi biết, Lisp đã có nó đầu tiên, và nó được gọi là lời khuyên trong Lisp. Lời khuyên là một khung công tác nhỏ cung cấp trước, xung quanh và sau các móc mà bạn có thể sửa đổi chương trình hành vi của một số hành động hoặc gọi hàm trong hệ thống.

Khác là special variables. Thông thường các macro (và các cấu trúc khác) áp dụng cho phạm vi từ vựng.Bằng cách tuyên bố một biến là đặc biệt, bạn đang yêu cầu nó áp dụng cho phạm vi động (tôi nghĩ nó là "phạm vi thời gian"). Tôi không thể nghĩ ra bất kỳ ngôn ngữ nào khác cho phép bạn (lập trình viên) lựa chọn giữa hai ngôn ngữ này. Và, ngoài trường hợp trình biên dịch, cả hai thực sự mở rộng không gian mà tôi quan tâm đến như một lập trình viên.

0

Tôi tin rằng các loại macro đó được gọi là macro đi bộ mã. Tôi đã không thực hiện một mã walker bản thân mình, vì vậy tôi không quen thuộc với các giới hạn.

0

Trong LISP chung, ít nhất, bạn có thể bao gồm các biểu mẫu cấp cao nhất trong PROGN và chúng vẫn giữ nguyên trạng thái của chúng dưới dạng các biểu mẫu cấp cao nhất (xem CLTL2, section 5.3). Do đó, giới hạn của một macro tạo ra một subtree đơn không có nhiều giới hạn vì nó có thể bọc bất kỳ số lượng các kết quả phụ trong PROGN. Điều này làm cho toàn bộ chương trình macro hoàn toàn có thể.

Ví dụ:

(my-whole-program-macro ...) 

= expands to => 

(progn 
    (load-system ...) 
    (defvar ...) 
    (defconstant ...) 
    (defmacro ...) 
    (defclass ...) 
    (defstruct ...) 
    (defun ...) 
    (defun ...) 
    ... 
) 
5

Trong vợt, bạn có thể thực hiện toàn bộ chương trình chuyển đổi macro. Xem phần trong tài liệu về defining new languages. Có rất nhiều ví dụ về điều này trong Racket, ví dụ như ngôn ngữ lười biếng và Typed Racket.