如何编写一个维护本地状态的宏?

时间:2011-08-09 06:56:52

标签: scheme r6rs

这似乎有效,它是一个宏,可以根据扩展的次数扩展到连续的整数。

;; Library (test macro-state)
(library
 (test macro-state)
 (export get-count incr-count)
 (import (rnrs))

 (define *count* 0)
 (define (get-count) *count*)
 (define (incr-count) (set! *count* (+ *count* 1)))

 )

;; Program
(import (rnrs) (for (test macro-state) expand))

(define-syntax m
  (lambda (x)
    (syntax-case x ()
      ((m) (begin (incr-count) (datum->syntax #'m (get-count)))))))

(write (list (m) (m) (m)))
(newline)
;; prints (1 2 3)

但这对我来说很笨拙,因为宏状态*count*和宏m本身位于不同的模块中。有没有更好的方法在r6rs中执行此操作,最好是不将实现分成两个模块的那个?

修改

我应该说清楚,尽管这个例子只是一个宏,但实际上我正在寻找一种在多个宏需要共享状态时有效的方法。

1 个答案:

答案 0 :(得分:5)

您可以将状态设置为宏变换器的本地状态:

(define-syntax m
  (let ()
    (define *count* 0)
    (define (get-count) *count*)
    (define (incr-count) (set! *count* (+ *count* 1)))
    (lambda (x)
      (syntax-case x ()
        ((m) (begin (incr-count) (datum->syntax #'m (get-count))))))))

已编辑添加:Racket中,您也可以这样做:

(begin-for-syntax
  (define *count* 0)
  (define (get-count) *count*)
  (define (incr-count) (set! *count* (+ *count* 1))))
(define-syntax m
  (lambda (x)
    (syntax-case x ()
      ((m) (begin (incr-count) (datum->syntax #'m (get-count)))))))

但我不认为R6RS有任何与begin-for-syntax相对应的内容。