Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Реализация макроса once-only 
:(
    Опции темы
GreenTea22
Дата 20.9.2009, 20:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 6.9.2009

Репутация: нет
Всего: нет



В книге Practical Common Lisp в конце главы про макросы
(http://gigamonkeys.com/book/macros-defining-your-own.html)
есть пример макроса, который обеспечивает расчет аргументов макроса 1 раз в заданном порядке
"
Another classic macro-writing macro is once-only, which is used to generate code that evaluates certain macro arguments once only and in a particular order. Using once-only, you could write do-primes almost as simply as the original leaky version, like this:

(defmacro do-primes ((var start end) &body body)
  (once-only (start end)
    `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
         ((> ,var ,end))
       ,@body)))

However, the implementation of once-only is a bit too involved for a blow-by-blow explanation, as it relies on multiple levels of backquoting and unquoting. If you really want to sharpen your macro chops, you can try to figure out how it works. It looks like this:

(defmacro once-only ((&rest names) &body body)
  (let ((gensyms (loop for n in names collect (gensym))))
    `(let (,@(loop for g in gensyms collect `(,g (gensym))))
      `(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
        ,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
           ,@body)))))
"
Я только начинаю изучать лисп и такой страшный макрос просто шокировал. Потом все таки с горем пополам разобрался как он работает.
А теперь ВОПРОС к уважаемым знатокам лиспа. В чем недостаток моей реализации этого макроса?

(defmacro my-once-only ((&rest names) &body body)
  `(let (,@(loop for n in names collect `(,n (eval ,n))))
    ,@body))

PM MAIL   Вверх
adejneka
Дата 21.9.2009, 05:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



DO-PRIMES с Вашей версией ONCE-ONLY производит вычисление аргументов START и END на этапе компиляции кода, использующего DO-PRIMES. Это работает только в том случае, когда аргументы - константные выражения без побочных эффектов, например, (DO-PRIMES (PRIME 11 99) ...). Если же значения этих аргументов должны определяться на этапе исполнения, особенно, если они имеют побочные эффекты, например, (DO-PRIMES (PRIME (AREF LOWER I) (PRINT (AREF UPPER (INCF I))) ...), то Ваш макрос не сработает:

Код

CL-USER> (let ((lower #(11 53 101))
               (upper #(10 40 70 200))
               (i 0))
           (do-primes (prime (aref lower i) (aref upper (incf i)))
             (print prime)))
; in: LAMBDA NIL
;     (DO-PRIMES (PRIME (AREF LOWER I) (AREF UPPER (INCF I))) (PRINT PRIME))

; caught ERROR:
;   (in macroexpansion of (DO-PRIMES (PRIME (AREF LOWER I) (AREF UPPER #)) (PRINT PRIME)))
;   (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
;   The variable LOWER is unbound.

;     (LET ((LOWER #(11 53 101)) (UPPER #(10 40 70 200)) (I 0))
;       (DO-PRIMES (PRIME (AREF LOWER I) (AREF UPPER (INCF I))) (PRINT PRIME)))


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума LISP
Void
  • Пожалуйста, создавайте темы с содержательными названиями.
  • Lisp — это целое семейство языков. Всегда указывайте в теме используемый диалект (Common Lisp, Scheme и т.д.).
  • Уважаемые учащиеся, здесь всегда рады помочь Вам, но не делать за Вас вашу работу. У вас гораздо больше шансов получить помощь, если Вы приложите усилия и поделитесь с нами проблемами и результатами. В противном случае добро пожаловать в раздел Центр Помощи.
  • Получив ответ на интересующий Вас вопрос, не забудьте пометить его как решённый.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Void.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | LISP | Следующая тема »


 




[ Время генерации скрипта: 0.0972 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.