在宏裏面的函數是在Guile和其他大多數Scheme方言中允許的。
但是,關鍵的問題是:哪些函數可用於宏在擴展過程中調出?
認爲它是這樣的:當編譯器正在處理您的代碼,它是第一家專注於將你的源代碼到的東西,可以在未來的某一時刻運行。但編譯器在編譯它們時可能不一定能夠執行那些相同的功能,同時您的宏正在運行並擴展了源代碼。
- 爲什麼不能提供這樣的功能?那麼,一個例子是:如果函數的主體使用了宏,那麼你在定義中呢?那麼你會有一個雞/雞蛋的問題。該函數需要運行要編譯的宏(因爲在編譯時需要擴展宏體中的宏)但是宏需要編譯的函數才能運行!
(此外,可能有一些功能,你只希望可在編譯時,爲您的宏幫忙,但你不希望可在運行時,使它將不會包含在您的程序可執行文件中,因爲這會浪費部署的二進制文件中的空間。)
我最喜歡的論文之一描述了這個問題,以及MzScheme採用的特定解決方案(現在稱爲球拍),是馬修弗拉特的論文"You Want It When"。
所以,這是任何計劃方言與程序宏系統具有處理在某些方面出了問題,而且狡詐也不例外。
在Guile的案例中,直接記錄在Guile手冊中的一個修正是使用eval-when
特殊形式,它允許您指定特定定義在哪些階段可用。
(其中「你想要它當」上面提到的論文描述了eval-when
一些問題,但因爲它是狡詐手動文件,我要堅持下去什麼了。我建議你瞭解eval-when
後,然後你看看Racket的解決方案,看看Guile是否提供類似的東西。)
所以你的情況,因爲你想要的process
功能,可在編譯時(在宏定義使用),你可以寫:
#!/usr/bin/guile -s
!#
(eval-when (expand)
(define (process body)
(list 'list (map (lambda (lst)
(list 'quote (car lst)))
body))))
(defmacro macro (body)
(list 'quote (process body)))
(display (macro ((foo bar) (bar baz))))
(newline)