2010-05-01 66 views
6

我經常發現有用的下列類型的增量定義的:增量宏定義可能嗎?

(define (foo) (display "bar")) 
(foo) 
;prints bar 
(define foo (let ((bar foo)) 
       (lambda() 
       (display "foo") 
       (bar)))) 

(foo) 
;prints foobar 

如何母材,宏這種類型的增量定義的? 我無法讓let-syntax提供相同的功能。

目前我使用plt方案,但希望在不同的lisp實現中看到答案。

編輯:

天真我想做到以下幾點:天真的宏

(define-syntax foo 
    (syntax-rules() 
    ((_) (display "bar")))) 

(define-syntax foo 
    (let-syntax ((old-foo (syntax-rules() ((_) (foo))))) 
    (syntax-rules() 
     ((_) (begin 
      (display "foo") 
      (old-foo)))))) 

轉換到工作PLT的計劃宏:

(require-for-syntax scheme/base) 
(define-syntax foo 
    (syntax-rules() 
    [(foo) (display "bar")])) 
(define-syntax foo 
    (let ([old (syntax-local-value #'foo)]) 
    (lambda (stx) 
     #`(begin #,((syntax-rules() 
       [(_) (begin (display "foo"))]) stx) 
      #,(old #'(_)))))) 
(foo) 

如果我缺少一個更好的方法讓我知道。

回答

2

FWIW(這絕對不是太大,因爲這是非常靶練習用雙腳練習),這裏是你如何只用衛生syntax-rules宏爲此在PLT的計劃:

(define-syntax foo 
    (syntax-rules() 
    [(foo x) (list 'x '= x)])) 
(define-syntax foo 
    (let ([old (syntax-local-value #'foo)]) 
    (compose (syntax-rules() 
       [(_ x ...) (list 'begin x ... 'end)]) 
      old))) 
(printf ">>> ~s\n" (foo (+ 1 2))) 

這不會在一個模塊裏面工作,只能在REPL上 - 那是一個好的的事情。在模塊中也可以做類似的事情,但是如果你想這樣做,你也可以使用程序宏(又名syntax-case宏),並在語法級別綁定一個標識符並設置「set!」 - 擴大它的價值。仍然不是一個好主意,仍然可能導致眼睛流血,但有些人喜歡傷害自己...

(哦,順便說一句 - 即使這樣做仍然是完全無關的問題的宏是否衛生與否。)

+1

謝謝,我必須包含(需要語法方案/基礎)才能在語法階段定義組合(要在定義語法中定義組合)。你可以評論我的天真方法(添加到問題)沒有實施?天氣是不是很實際,或者它與現有的語法不一致? – Davorak 2010-05-04 04:09:32

+1

是的,你需要'計劃/基地'來組成;但是您可以按任何您想要的方式組合宏函數 - 它們只是從語法到語法的函數,而'syntax-rules'是生成此類函數的方便(通常爲第2級)宏。 至於你的幼稚方法,它有一些基本的問題:它試圖以某種方式捕獲舊的語法,但你不能以這種方式得到它的*值*,所以結果是一個擴展到調用自身的宏。另一個問題是在試圖使用'display'來調試東西 - 宏不會*做*它,他們會*擴大*。 – 2010-05-04 04:35:17

+0

謝謝,我知道我無法以這種方式捕捉舊的語法,並且它會擴展到自己。我只是認爲它很好地處理了我熟悉的語法,並想知道爲什麼它存在於函數層次,爲什麼它不存在於宏觀層面,即使似乎沒有任何根本阻止編譯器以這種方式行事。我試圖使用顯示作爲測試,看看宏是否構建正確,我編輯我的問題翻譯我的天真宏到一個工作的PLT計劃宏。 – Davorak 2010-05-04 08:35:57

3

使用這個宏,你正在創建最難維護的軟件在這個星球上。

編輯:在Common Lisp中是可以的。我不記得我曾經見過它在源代碼中使用過。

在Common Lisp社區中,通常將函數或宏的行爲稱爲'advise'或'advice'。一些「建議」工具也可以爲宏提供建議。

+0

目前沒有我Scheme程序有什麼用關鍵任務,甚至我個人工作流程。此外,我上面的增量定義可以很容易地變成一個Python函數裝飾器。所以我的問題措辭的另一種方式是宏裝飾可能? – Davorak 2010-05-01 09:28:48

+0

@Davorak:你裝飾裝飾? – outis 2010-05-01 11:20:02

+0

在python裝飾器可以用於裝飾器的定義,而我沒有機會在我自己的代碼中使用它們,我會看到它是如何有用的。只是爲了確保我以前的評論清楚我的宏裝飾器的意思是一個可以用來裝飾另一個宏的宏。 – Davorak 2010-05-01 11:30:26

3

我不認爲你可以用宏來做這樣的事情。我也沒有看到任何嘗試。

請注意,宏不只是一些額外的魔術功能!宏是完全不同的。

也許你正在尋找像Common Lisp中的方法組合?

+0

謝謝。你是否也沒有看到功能性案例中的觀點?或者在Python中裝飾器的情況?它有用嗎?或者爲什麼它對宏特別沒有用?......現在我已經讀了一些關於方法組合的內容,它們似乎提供了Python中裝飾器的相同功能。爲什麼這種抽象級別對函數有用但對宏沒有意義? – Davorak 2010-05-01 10:59:25

+0

@Davorak:裝飾器與方法組合的功能截然不同。裝飾器在定義時執行,而組合方法在調用方法時執行。後者是面向方面編程的重要組成部分。如果有的話,裝飾器更類似於宏,但在更有限的情況下使用。 – outis 2010-05-01 11:18:38

+0

你似乎描述的是實現差異而非功能差異。我可以使用裝飾器在函數之前,之後或周圍運行額外的代碼或完全覆蓋它。這就像我通過閱讀規範所理解的方法組合,您可以使用方法組合在現有函數之前,之後或周圍運行額外的代碼。 – Davorak 2010-05-01 11:37:49

0

let*怎麼樣?

(define foobar 
    (let* ((foo (lambda() (display "foo"))) 
      (bar (lambda() (foo) (display "bar")))) 
      bar)) 
+0

謝謝,但我認爲你誤解了這個問題。我感興趣的是能夠改變全局變量的定義,而上面只是局部的。另外,我的問題是如何處理宏。 – Davorak 2010-05-01 17:25:45

1

我想你可以通過使用不衛生的宏,我相信PLT計劃支持。那麼你將使用與常規函數完全相同的機制,因爲宏將是正常的函數,它發生在S表達式上。

我不知道如何用衛生的宏做這件事,但我很驚訝你不能 - 我會考慮在PLT郵件列表上提問。

+0

謝謝,我會嘗試在某個時候詢問郵件列表。如果可能在plt中使用不衛生的宏,我仍然會感到驚訝,但很高興。我試圖用defmacro做出答案,但還沒有找到答案,雖然我不是defmacro的專家。 – Davorak 2010-05-01 17:33:08

+2

它*可以在PLT中實現 - 它們的關鍵不在於宏是否衛生,而是具有程序宏觀層和一些反映功能。 – 2010-05-04 00:39:54