Я часто нахожу следующий тип возрастающего определения полезным:
(define (foo) (display "bar"))
(foo)
;prints bar
(define foo (let ((bar foo))
(lambda ()
(display "foo")
(bar))))
(foo)
;prints foobar
Как я формую этот тип возрастающего определения с макросами? Я не мог заставить позволенный синтаксис обеспечивать ту же функциональность.
В настоящее время я использую plt схему, но хотел бы видеть ответы в различных реализациях шепелявости также.
Править:
Наивно я хотел бы сделать следующее:
(define-syntax foo
(syntax-rules ()
((_) (display "bar"))))
(define-syntax foo
(let-syntax ((old-foo (syntax-rules () ((_) (foo)))))
(syntax-rules ()
((_) (begin
(display "foo")
(old-foo))))))
Перевод наивных макросов к работе plt макросы схемы:
(require-for-syntax scheme/base)
(define-syntax foo
(syntax-rules ()
[(foo) (display "bar")]))
(define-syntax foo
(let ([old (syntax-local-value #'foo)])
(lambda (stx)
#`(begin #,((syntax-rules ()
[(_) (begin (display "foo"))]) stx)
#,(old #'(_))))))
(foo)
Если я пропускаю лучший сообщенный мне метод.
FWIW (и это определенно не много, так как это в значительной степени упражнение по тренировке мишеней ногами), вот как вы бы сделали это в схеме PLT с помощью только макросов гигиенических синтаксических правил
:
(define-syntax foo
(syntax-rules ()
[(foo x) (list 'x '= x)]))
(define-syntax foo
(let ([old (syntax-local-value #'foo)])
(compose (syntax-rules ()
[(_ x ...) (list 'begin x ... 'end)])
old)))
(printf ">>> ~s\n" (foo (+ 1 2)))
Это не будет работать внутри модуля, только на REPL - и это хорошо . Можно сделать что-то подобное и в модулях, но если вы собираетесь это сделать, вы также можете использовать процедурные макросы (также известные как макрос синтаксиса syntax-case
) с идентификатором, привязанным к уровень синтаксиса и `set! '- указав его значение, чтобы расширить его. Все еще не лучшая идея и все еще может привести к кровотечению из глаз, но некоторым людям нравится причинять себе вред ...
(О, и кстати - даже это все еще совершенно не связано с тем, являются ли рассматриваемые макросы гигиеничными или нет.)
С помощью макросов вы на пути к созданию самого сложного в обслуживании программного обеспечения на планете.
Изменить: в Common Lisp это возможно. Я не могу вспомнить, чтобы когда-нибудь видел, чтобы это использовалось в исходном коде.
Добавление поведения к функциям или макросам часто называется «советом» или «советом» в сообществе Common Lisp. Некоторые инструменты «советовать» также могут давать советы по макросам.
Как насчет let * ?
(define foobar
(let* ((foo (lambda () (display "foo")))
(bar (lambda () (foo) (display "bar"))) )
bar))
Я думаю, вы могли бы добиться этого, используя негигиеничные макросы, которые, как я полагаю, поддерживает PLT Scheme. Тогда вы будете использовать точно такие же механизмы, как и при работе с обычными функциями, поскольку макросы будут обычными функциями, которые работают с S-выражениями.
Я не знаю, как это сделать с гигиеническими макросами, но я весьма удивлен, что вы не можете - я бы подумал о том, чтобы спросить в списке рассылки PLT.
Я не думаю, что вы можете сделать что-то подобное с помощью макросов. Я тоже не вижу смысла пытаться.
Обратите внимание, что макросы - это не просто некоторые функции с дополнительной магией ! Макросы - это совсем другое дело.
Возможно, вы ищете что-то вроде комбинаций методов в Common Lisp?