UP | HOME

syntax-property 與 local-expand 的實際運用

syntax-property 可以用來把資訊存入 syntax 中,這可以用在各種有趣的 macro 擴展系統之中。一個我比較熟悉的案例是 type-system,比如我們可以寫下

(define-syntax-parser Nat
  [_ (syntax-property #''Nat 'type #'Type)])
(define-syntax-parser zero
  [_ (syntax-property #''zero 'type #'Nat)])
(define-syntax-parser succ
  [(_ n)
   (check-type #'n #'Nat)
   (syntax-property #'`(succ ,n) 'type #'Nat)])

來表示

data Nat =
  zero
  succ Nat

其中 check-type 可以用

(define (typeof stx)
  (syntax-property (local-expand stx 'expression '()) 'type))

來取得型別。 這是因為有一個常見的問題:marco 是由外往內處理的,然而我們的程式是要模擬由內往外的語意。這時候我們就會不知道 #'n 到底是什麼玩意兒,這裡用 local-expand 先展開之後,才會知道它原始的 syntax 是什麼。所以如果我們直接寫:

(define-syntax-parser succ
  [(_ n)
   (displayln (syntax-property #'n 'type))
   (syntax-property #``(succ ,#,(local-expand n 'expression '())) 'type #'Nat)])

我們會得到 #f 而非 #'Nat=。而 =#'Nat 之巧妙就在於這時候如果我們寫:

(syntax-property (local-expand (syntax-property (local-expand #'n 'expression '()) 'type) 'expression '()) 'type)

會得到 =#'Type=。

Date: 2021-08-19 Thu 00:00
Author: Lîm Tsú-thuàn