2011-01-21 67 views
6

我見過的How does Lisp let you redefine the language itself? 堆棧溢出的問題(由諾亞拉文回答)一個答案:Lisp或Scheme中是否有整個程序轉換宏?

宏是不是語言的相當完整的重新界定,至少就我所知(I」實際上是一個Schemer;我可能是錯的),因爲有一個限制。宏只能取代碼的單個子樹,並生成一個子樹來替換它。因此,你不能編寫完整的程序轉換宏,就像那樣酷。

閱讀完本文後,我對Lisp或Scheme(或其他語言)中是否存在「整個程序轉換宏」感到好奇。

如果不是那麼爲什麼?

  • 這不是有用的,從來沒有要求?
  • 同樣的事情可以通過其他方式實現嗎?
  • 即使在Lisp中也不可能實現它嗎?
  • 這是可能的,但沒有嘗試或實施過?

更新

一種使用情況 例如

正如stumpwm代碼 這裏有一些功能,都在不同的LISP源文件 使用動態/全局變量defvar * 屏幕列表*是在primitives.lisp定義,但在屏幕使用。 lispuser.lispwindow.lisp。 (這裏的每個文件都函數,類,乏相關的一個方面或對象)

現在,我想封下定義這些功能,其中 *屏幕列表*變量可通過讓利的形式,它不應該是 動態/全局變量,但沒有移動這些所有功能到 一個地方(因爲我不希望這些功能從他們的 相關文件丟失) 因此,這個變量將只能訪問這些功能。

上方例如同樣適用於標籤和flet,因此它將進一步可能使 我們可以使它變成只有需要的變量,函數將可用, 給那些需要它的人。

注意一種方式可能是 實現並使用一些宏defun_with_context defun其中第一個參數是 上下文其中let,flet變量definend。 但除此之外,它可以通過讀者宏來實現,如 Vatine和Gareth Rees回答。

回答

5

您援引諾亞拉文的話說:

宏只能把你的代碼的單個子樹,並生成一個子樹來取代它

這是普通宏的情況下,但閱讀器宏可以訪問輸入流,並可以對它進行任何操作。

請參閱Hyperspec section 2.2set-macro-character函數。

0

總是有使用編譯器宏的選擇(它們可以基於標準的lew進行全功能轉換,但不應該改變返回的值,因爲這會造成混淆)。

有讀者宏,他們轉換輸入「,因爲它被讀取」(或「之前它被讀取」,如果你喜歡)。我沒有做過大規模的閱讀器宏攻擊,但我已經編寫了一些代碼,允許elisp sourec(大部分)在Common Lisp中讀取,兩者之間的語法糖含有很多細微的差異。

1

一個典型的方法是編寫你自己的模塊系統。如果你只是想訪問所有的代碼,你可以有一些預處理器或閱讀器擴展包裝源文件與你自己的模塊註釋。如果您隨後編寫自己的requireimport表單,您最終將能夠看到範圍內的所有代碼。

要開始,您可以編寫自己的module表單,該表單允許您定義幾個函數,然後在發出優化代碼之前以某種巧妙方式編譯。

1

關閉我的頭頂,有幾個方法:

首先,你可以。 Norvig points out即:

我們可以編寫一個編譯器作爲一組宏。

所以你可以轉換整個程序,如果你想。我只看到它很少做,因爲通常「你想要做的事情到你的程序的每個部分」和「你需要宏/ AST類型轉換的東西」之間的交集是一個很小的集合。一個例子是Parenscript,它將您的Lisp代碼(「CL的擴展子集」)轉換爲Javascript。我用它將Lisp代碼的整個文件編譯成直接提供給Web客戶端的Javascript。這不是我最喜歡的環境,但它做它宣傳的東西。

另一個相關的特徵是 「建議」,其中Yegge describes as

大系統也有意見。這個功能沒有普遍接受的名稱。有時它被稱爲鉤子或過濾器或面向方面的編程。據我所知,Lisp第一,它在Lisp中被稱爲建議。建議是一個小型框架,它在鉤子之前,之後和之後提供,通過這些框架可以以編程方式修改系統中某些動作或函數調用的行爲。

另一個是special variables。通常宏(和其他構造)適用於詞法範圍。通過聲明一個變量是特殊的,你告訴它適用於動態範圍(我認爲它是「時間範圍」)。我想不出任何其他語言可以讓你(程序員)在這兩種語言之間進行選擇。而且,除了編譯器外,這兩個實際上還是我作爲程序員感興趣的空間。

0

我相信這些類型的宏被稱爲代碼行走宏。我自己還沒有實現代碼步行者,所以我不熟悉這些限制。

0

在通常的LISP中,至少可以在PROGN中包裝頂層窗體,並且它們仍然保持其狀態爲頂層窗體(請參閱CLTL2, section 5.3)。因此,生成單個子樹的宏的限制並不是很有限,因爲它可以在PROGN內包裝任何數量的結果子樹。這使得整個程序宏很可能。

E.g.

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

= expands to => 

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

在Racket中,您可以實現整個程序轉換宏。請參閱有關defining new languages的文檔中的部分。在Racket中有很多這樣的例子,例如懶惰的語言和類型化的球拍。