2010-05-01 4 views
6

Я часто следующий типа дополнительного определения полезного:Возможно ли инкрементное определение макросов?

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

(foo) 
;prints foobar 

Как преформы этого типа дополнительного определения с макросами? Я не мог получить let-syntax для обеспечения той же функциональности.

В настоящее время я использую схему 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) 

Если я пропускаю лучший метод дай мне знать.

ответ

2

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

(Ох, и BTW - даже не делая это до сих пор полностью не связанно ли макросы в вопросе гигиеничны или нет.)

+1

Спасибо, я должен был включить (require-for-syntax scheme/base), чтобы компиляция была определена в фазе синтаксиса? (Чтобы сделать compose определен в определении-синтаксисе). Можете ли вы прокомментировать мой наивный подход (добавленный к вопросу), не реализован? Погода непрактична или как она несовместима с существующим синтаксисом? – Davorak

+1

Да, вам нужно «схема/база», чтобы получить композицию; но вы можете комбинировать макрофункции любым способом - это просто функции от синтаксиса до синтаксиса, а «синтаксические правила» - это удобный (обычно второй) макрос, который генерирует такие функции. Что касается вашего наивного подхода, он сталкивается с некоторыми фундаментальными проблемами: он пытается каким-то образом захватить старый синтаксис, но вы не можете получить его * значение * таким образом, поэтому результатом будет макрос, который расширяется до вызовов к себе. Другая проблема заключается в попытке использовать 'display' для отладки файлов - макросы не будут * делать * это, они будут * расширять * на него. –

+0

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

3

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

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

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

+0

Currently ничего Программирует со схемой не имеет ничего общего с критически важными или даже моим личным рабочий поток. Также инкрементное определение, которое я выше, может легко стать декоратором, подобным функции на основе python. Итак, другой способ формулировки моего вопроса будет заключаться в возможности создания макродекораторов? – Davorak

+0

@ Davorak: Вы украшаете декораторы? – outis

+0

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

3

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

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

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

+0

Спасибо. Вы также не видите смысла в функциональном случае? Или случай для декораторов в питоне? Полезно ли это? Или почему это не полезно для макросов в частности? ... Теперь, когда я немного ознакомился с комбинациями методов, они, похоже, обеспечивают одинаковые функциональные возможности декораторов в python. Почему этот уровень абстракции полезен для функций, но бессмыслен для макросов? – Davorak

+0

@ Davorak: декораторы отличаются функциональностью от комбинаций методов. Декораторы выполняются при определении, тогда как комбинированные методы выполняются при вызове метода. Последние являются неотъемлемой частью аспектно-ориентированного программирования. Во всяком случае, декораторы больше похожи на макросы, но используются в более ограниченных условиях. – outis

+0

Что вы, кажется, описываете, это разница в реализации, а не разница в функциональности. Я могу использовать декоратор для запуска дополнительного кода до, после или вокруг функции или полностью переопределить его. Это похоже на комбинации методов в моем понимании от чтения спецификации, что вы можете использовать комбинацию методов для запуска дополнительного кода до, после или вокруг существующей функции. – Davorak

0

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

(define foobar 
    (let* ((foo (lambda() (display "foo"))) 
      (bar (lambda() (foo) (display "bar")))) 
      bar)) 
+0

Спасибо, но я думаю, что вы неправильно поняли вопрос. Я был заинтересован в возможности изменить определение глобальной переменной, в то время как выше это только локально. Кроме того, мой вопрос заключался в том, как это можно сделать с макросами. – Davorak

1

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

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

+0

Спасибо, я попробую расспросить список рассылки в какой-то момент. Я все равно был бы удивлен, если бы это было возможно с негигиеничными макросами в plt, но доволен. Я попытался дать ответ с defmacro, но не смог понять ответ, хотя я не эксперт по defmacro. – Davorak

+2

Это * возможно сделать в PLT - они не связаны с макросами, которые являются гигиеничными или нет, но с процедурным макрослотом и некоторыми отражающими возможностями, которые идут с ним. –

Смежные вопросы