Макроопределяющий макрос в Racket?
В Common Lisp относительно легко создать макрос, определяющий макрос. Например, следующий макрос
(defmacro abbrev (short long)
`(defmacro ,short (&rest args)
`(,',long ,@args)))
является макросом, определяющим макрос, потому что он расширяется до другого макроса.
Если мы сейчас поставим
(abbrev def defun)
в нашей программе мы можем написать def
вместо defun
всякий раз, когда мы определяем новую функцию. Конечно, abbrev
можно использовать и для других вещей. Например, после
(abbrev /. lambda)
мы можем написать (/. (x) (+ x 1))
вместо (lambda (x) (+ x 1))
, Ницца. (Подробное описание сокращений см. По http://dunsmor.com/lisp/onlisp/onlisp_20.html).
Теперь мои вопросы:
- Могу ли я написать макроопределение макросов в Racket?
- Если я могу, как это сделать? (например, как написать что-то похожее на
abbrev
макрос в ракетке?)
3 ответа
Согласно этой части руководства по ракеткам:
(define-syntax-rule (abbrev short long)
(define-syntax-rule (short body (... ...))
(long body (... ...))))
Цитируя приведенную выше ссылку:
Единственной неочевидной частью его определения является (... ...), который "заключает в кавычки"... так что он принимает свою обычную роль в сгенерированном макросе, а не в генерирующем макросе.
Сейчас
(abbrev def define)
(abbrev /. lambda)
(def f (/. (x) (+ x 1)))
(f 3)
доходность
4
FWIW, он работает и на Guile, так что это не относится к Racket.
Объявление 1. Да. объявление 2. Ваш пример легче всего написать
#lang racket
(define-syntax (abbrev stx)
(syntax-case stx ()
[(_ short long)
#'(define-syntax short (make-rename-transformer #'long))]))
(abbrev def define)
(def x 42)
x
Пример выше оценивает 42.
Я считаю, что переименование может быть сделано просто с помощью операторов define или let:
(define =? =)
(define lr list-ref)
или же:
(let ((=? =)
(lr list-ref))
(println (lr '(1 2 3) 2))
(println (=? 1 2))
(println (=? 1 1)))
Выход:
3
#f
#t
Кажется, для этой цели не требуется никакой макрос.