Примеры того, для чего могут использоваться макросы Lisp

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

Кто-либо может дать некоторые примеры?

31
задан Dimitri C. 1 April 2010 в 14:46
поделиться

7 ответов

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

Посмотрите очень хорошую онлайн-книгу Practical Common Lisp, чтобы ознакомиться с практическими примерами.

7. Макросы: стандартные конструкции управления
8. Макросы: Определение собственного

3
ответ дан 27 November 2019 в 21:59
поделиться

Преобразования исходного кода. Все виды. Примеры:

  • Новые операторы потока управления : Вам нужен оператор WHILE? На вашем языке его нет? Зачем ждать, когда доброжелательный диктатор, возможно, добавит еще один в следующем году. Напишите сами. В течение пяти минут.

  • Более короткий код : вам нужно двадцать объявлений классов, которые выглядят почти одинаково - отличается лишь ограниченное количество мест. Напишите форму макроса, которая принимает различия в качестве параметра и генерирует для вас исходный код. Хотите изменить это позже? Поменять макрос в одном месте.

  • Замены в исходном дереве : Вы хотите добавить код в исходное дерево? Переменная действительно должна быть вызовом функции? Оберните макрос вокруг кода, который «обходит» источник и меняет места, где он находит переменную.

  • Синтаксис постфикса : Вы хотите написать свой код в форме постфикса? Используйте макрос, который переписывает код в нормальную форму (префикс в Лиспе).

  • Эффекты времени компиляции : Вам нужно запустить некоторый код в среде компилятора, чтобы сообщить среде разработки об определениях? Макросы могут генерировать код, который запускается во время компиляции.

  • Упрощения / оптимизации кода во время компиляции : Вы хотите упростить некоторый код во время компиляции? Используйте макрос, который делает упрощение - таким образом вы можете переключить работу со времени выполнения на время компиляции на основе исходных форм.

  • Генерация кода из описаний / конфигураций : Вам нужно написать сложное сочетание классов. Например, у вашего окна есть класс, у субпанелей есть классы, между панелями есть ограничения пространства, у вас есть цикл команд, меню и множество других вещей. Напишите макрос, который фиксирует описание вашего окна и его компонентов и создает классы и команды, управляющие приложением - из описания.

  • Улучшения синтаксиса : Какой-то синтаксис языка выглядит не очень удобным? Напишите макрос, который сделает его более удобным для вас, разработчика приложения.

  • Доменные языки : Вам нужен язык, более близкий к домену вашего приложения? Создавайте необходимые языковые формы с помощью набора макросов.

Мета-лингвистическая абстракция

Основная идея: все, что есть на лингвистическом уровне (новые формы, новый синтаксис, преобразования форм, упрощение, поддержка IDE, ...) теперь может программироваться разработчиком по частям - без отдельной стадии обработки макросов.

42
ответ дан 27 November 2019 в 21:59
поделиться

Помимо расширения синтаксиса языка, позволяющего более четко выражать свои мысли, он также дает вам контроль над оценкой. Попробуйте написать свой собственный if на выбранном вами языке, чтобы вы могли действительно написать my_if something my_then print "success" my_else print "failure" и чтобы оба оператора print не оценивались. На любом строгом языке без достаточно мощной макросистемы это невозможно. Однако ни один программист на Common Lisp не сочтет эту задачу слишком сложной. То же самое для для -циклов, циклов foreach, и т. Д. Вы не можете выразить эти вещи на C, потому что они требуют специальной семантики оценки (люди фактически пытались ввести foreach ] в Objective-C, но это не сработало), но они почти тривиальны в Common Lisp из-за его макросов.

3
ответ дан 27 November 2019 в 21:59
поделиться

Выберите любой « инструмент генерации кода ». Прочтите их примеры. Вот что он умеет.

За исключением того, что вам не нужно использовать другой язык программирования, помещать какой-либо код расширения макроса, где используется макрос, запускать отдельную команду для сборки или иметь на жестком диске дополнительные текстовые файлы, которые представляют только ценность к вашему компилятору.

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

9
ответ дан 27 November 2019 в 21:59
поделиться

Просто предположение - доменные языки.

2
ответ дан 27 November 2019 в 21:59
поделиться

Что-нибудь, что вы обычно хотели бы сделать в препроцессоре?

Один макрос, который я написал, предназначен для определения конечных автоматов для управления игровыми объектами. Проще читать код (используя макрос), чем читать сгенерированный код:

(def-ai ray-ai
  (ground
   (let* ((o (object))
          (r (range o)))
     (loop for p in *players*
           if (line-of-sight-p o p r)
           do (progn
                (setf (target o) p)
                (transit seek)))))
  (seek
   (let* ((o (object))
          (target (target o))
          (r (range o))
          (losp (line-of-sight-p o target r)))
     (when losp
       (let ((dir (find-direction o target)))
         (setf (movement o) (object-speed o dir))))
     (unless losp
       (transit ground)))))

Чем читать:

(progn
 (defclass ray-ai (ai) nil (:default-initargs :current 'ground))
 (defmethod gen-act ((ai ray-ai) (state (eql 'ground)))
            (macrolet ((transit (state)
                         (list 'setf (list 'current 'ai) (list 'quote state))))
              (flet ((object ()
                       (object ai)))
                (let* ((o (object)) (r (range o)))
                  (loop for p in *players*
                        if (line-of-sight-p o p r)
                        do (progn (setf (target o) p) (transit seek)))))))
  (defmethod gen-act ((ai ray-ai) (state (eql 'seek)))
            (macrolet ((transit (state)
                         (list 'setf (list 'current 'ai) (list 'quote state))))
              (flet ((object ()
                       (object ai)))
                (let* ((o (object))
                       (target (target o))
                       (r (range o))
                       (losp (line-of-sight-p o target r)))
                  (when losp
                    (let ((dir (find-direction o target)))
                      (setf (movement o) (object-speed o dir))))
                  (unless losp (transit ground)))))))

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

4
ответ дан 27 November 2019 в 21:59
поделиться

R , стандартный язык программирования статистики, имеет макросы ( руководство R, глава 6 ). Вы можете использовать это для реализации функции lm () , которая анализирует данные на основе модели, указанной вами как код.

Вот как это работает: lm (Y ~ aX + b, data) попытается найти параметры a и b , которые лучше всего подходят для ваших данных. Самое интересное, что вы можете заменить aX + b любым линейным уравнением, и оно все равно будет работать. Это прекрасная возможность упростить вычисление статистики, и она работает так элегантно только потому, что lm () может анализировать данное уравнение, что и делают макросы Lisp.

3
ответ дан 27 November 2019 в 21:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: