Как написать макрос, который поддерживает локальное состояние?
Кажется, это работает, это макрос, который расширяется до последовательных целых чисел в зависимости от того, сколько раз он был расширен.
;; 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 ответ
Вы можете сделать состояние локальным для макротрансформатора:
(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
,