假設我想在球拍/方案中定義一個工具「定義」的宏。具體來說,它計算定義體中的數字文字,然後將此數字添加到所有這些文字(這應發生在宏觀擴展階段)。如何用模板宏重寫這個宏?
這是一個正常功能的風格(如列表上的語法樹操作)中定義的宏:我想重寫它在正常球拍/方案模板的宏風格
#lang racket
(require
(for-syntax racket/syntax)
(rename-in racket [define define/racket]))
(define-for-syntax (count-and-transform e)
(define tree (syntax->datum e))
; count number literals
(define (count t)
(if (list? t)
(apply + (map count t))
(if (number? t) 1 0)))
(define n (count tree))
; transform number literals
(define (transform t)
(if (list? t)
(map transform t)
(if (number? t) (+ t n) t)))
(values n (datum->syntax e (transform tree))))
; rewrite defines
(define-syntax (define stx)
(syntax-case stx()
[(_ signature body)
(let-values ([(n new-body)
(count-and-transform #'body)])
#`(begin
(display "number of literals in function ")
(display 'signature) (display ": ") (displayln #,n)
(define/racket signature #,new-body)))]))
(define (add-some x) (if (= x 0) (+ x 1) 2))
。這裏是我的(失敗)嘗試:
#lang racket
(require
(for-syntax racket/syntax)
(rename-in racket [define define/racket]))
(define-for-syntax n 0)
; rewrite defines
(define-syntax-rule
(define signature body)
(begin
(display "number of literals in function ")
(display 'signature) (display ": ") (display-counted-n)
(define/racket signature (descent body))))
; descent the syntax tree and mark all nodes
(define-syntax descent
(syntax-rules (f-node a-node)
[(_ (f etc ...)) (mark (f (descent etc) ...))]
[(_ a etc ...) (mark a (descent etc) ...)]))
; count number literals
(define-syntax (mark stx)
(syntax-case stx()
[(_ node)
(begin
;(display n) (display " : ") (displayln (syntax->datum #'node))
(if (number? (syntax-e #'node))
(begin
(set! n (add1 n))
#'(transform node))
#'node))]))
; transform number literals
(define-syntax (transform stx)
(syntax-case stx()
[(_ node)
(let* ([i (syntax->datum #'node)]
[i+n (+ i n)])
(begin
;(display i) (display " -> ") (displayln i+n)
(datum->syntax stx i+n)))]))
(define-syntax (display-counted-n stx)
(syntax-case stx()
[(_) #`(displayln #,n)]))
(define (add-some x) (if (= x 0) (+ x 11) 13))
的想法是分階段儀器代碼:首先標誌着語法樹的所有節點,再算上文字,以「改造」,其中需要更換宏觀痕跡......好吧,正如所評論的「顯示」將顯示的那樣,宏「標記」在所有「下降」完成之前開始擴展(因此它們仍然處於由宏代碼捕獲的狀態)。即使「display-counting-n」擴展得太快,而「n」仍然是0.
有沒有辦法改變宏擴展的順序?我希望球拍/方案分階段進行擴展:首先是「下降」,然後是「標記」,然後是「變形」,然後是「顯示計數-n」。
我讀過How to control order of Scheme macro expansion?的答案 - 看起來用模板宏來實現這樣一個任務的唯一方法是使用「祕密文字」並在一個大的宏定義中定義所有的東西。不過,我想這會讓代碼更難寫和讀。有沒有其他的方式,也許?
謝謝克里斯。我將學習擋泥板和語法分析...如果我們不能使用2個單獨的#體(如上所述)副本,會有什麼辦法?例如,如果我們1)使用(generate-temporary)生成的帶有id-s的語法樹的工具(一些)節點; 2)必須以某種方式將運行時間轉移到這些id-s的列表。 – formalizm
@formalizm我不確定你真的想要做什麼。你可能想問一個關於這個問題的新問題,並詳細說明你正在嘗試做什麼。 :-) –
經過一番思考我管理。也許以後我會問一些新的問題。謝謝。) – formalizm