Как написать макрос, который поддерживает локальное состояние?

Кажется, это работает, это макрос, который расширяется до последовательных целых чисел в зависимости от того, сколько раз он был расширен.

;; 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, предпочтительно тот, который не разделяет реализацию на два модуля?

ИЗМЕНИТЬ

Я должен пояснить, что, хотя этот пример — всего лишь один макрос, на самом деле я ищу метод, который работает, когда несколько макросов должны совместно использовать состояние.


person john    schedule 09.08.2011    source источник


Ответы (1)


Вы можете сделать состояние локальным для макропреобразователя:

(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.

person Ryan Culpepper    schedule 09.08.2011
comment
Да, я думал об этом после того, как написал. Но обобщает ли этот метод, если вы хотите, чтобы несколько макросов совместно использовали состояние? - person john; 09.08.2011
comment
@john, нет, и я не знаю ничего другого в R6RS, что могло бы помочь. Смотрите также мой отредактированный ответ. - person Ryan Culpepper; 09.08.2011