Возможно ли инкрементальное макроопределение? - PullRequest
6 голосов
/ 01 мая 2010

Я часто нахожу следующий тип добавочного определения полезным:

(define (foo) (display "bar"))
(foo)
;prints bar
(define foo (let ((bar foo))
              (lambda ()
                (display "foo")
                (bar))))

(foo)
;prints foobar

Как мне преобразовать этот тип инкрементального определения с помощью макросов? Мне не удалось получить синтаксис let для обеспечения той же функциональности.

В настоящее время я использую схему plt, но хотел бы видеть ответы и в других реализациях lisp.

Edit:

Наивно я хотел бы сделать следующее:

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

Если мне не хватает лучшего метода, дайте мне знать.

Ответы [ 5 ]

3 голосов
/ 01 мая 2010

Я не думаю, что вы можете сделать что-то подобное с макросами. Я тоже не вижу смысла в попытках.

Обратите внимание, что макросы - это не просто некоторые функции с дополнительной магией ! Макросы - это совсем другое.

Возможно, вы ищете что-то вроде комбинации методов в Common Lisp?

3 голосов
/ 01 мая 2010

Используя макросы, вы на пути к созданию самого сложного в обслуживании программного обеспечения на планете.

Редактировать: в Common Lisp это возможно. Я не могу вспомнить, чтобы я когда-либо видел его в исходном коде.

Добавление поведения к функциям или макросам в сообществе Common Lisp часто называется «советовать» или «советовать». Некоторые инструменты «посоветовать» также имеют возможность посоветовать макросы.

2 голосов
/ 04 мая 2010

FWIW (и это определенно не так много, так как это в значительной степени упражнение для тренировки с ногами), вот как вы бы это делали в схеме PLT только с гигиеническими syntax-rules макросами:

(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! '-это его значение, чтобы расширить его. Все еще не лучшая идея, и все еще может привести к кровотечению глаз, но некоторые люди любят ранить себя ...

(Да, и кстати - даже выполнение этого все еще совершенно не связано с тем, являются ли рассматриваемые макросы гигиеническими или нет.)

1 голос
/ 01 мая 2010

Я думаю, вы могли бы получить это, используя негигиеничные макросы, которые, как я считаю, поддерживает схема PLT. Тогда вы будете использовать те же механизмы, что и с обычными функциями, поскольку макросы будут обычными функциями, которые работают с S-выражениями.

Я не знаю, как это сделать с гигиеническими макросами, но я очень удивлен, что вы не можете - я бы подумал спросить в списке рассылки PLT.

0 голосов
/ 01 мая 2010

А как насчет let *?

(define foobar
    (let* ((foo (lambda () (display "foo")))
           (bar (lambda () (foo) (display "bar"))) )
            bar))
...