Метапрограммирование - Википедия - Metaprogramming

Метапрограммирование это метод программирования, в котором компьютерные программы имеют возможность рассматривать другие программы как свои данные. Это означает, что программа может быть разработана для чтения, генерации, анализа или преобразования других программ и даже для изменения самой себя во время работы.[1][2] В некоторых случаях это позволяет программистам минимизировать количество строк кода для выражения решения, что, в свою очередь, сокращает время разработки.[3] Это также обеспечивает большую гибкость программ для эффективной обработки новых ситуаций без перекомпиляции.

Метапрограммирование может использоваться для переноса вычислений из время выполнения к время компиляции, для генерации кода с использованием вычислений во время компиляции и для включения самомодифицирующийся код. Язык, на котором написана метапрограмма, называется метаязык. Язык управляемых программ называется атрибутивно-ориентированное программирование язык. Способность языка программирования быть собственным метаязыком называется отражение или «рефлексивность».[4] Отражение - это ценная языковая функция, облегчающая метапрограммирование.

Метапрограммирование было популярно в 1970-х и 1980-х годах с использованием языков обработки списков, таких как LISP. Аппаратные машины LISP были популярны в 1980-х годах и позволяли приложениям обрабатывать код. Их часто использовали для искусственный интеллект Приложения.

Подходы

Метапрограммирование позволяет разработчикам писать программы и разрабатывать код, подпадающий под общее программирование парадигма. Имея сам язык программирования как первоклассный тип данных (как в Лисп, Пролог, СНОБОЛ, или же Ребол ) тоже очень полезно; это известно как гомоиконность. Универсальное программирование вызывает средство метапрограммирования в языке, позволяя писать код, не заботясь об указании типов данных, поскольку они могут быть предоставлены как параметры при использовании.

Метапрограммирование обычно работает одним из трех способов.[5]

  1. Первый подход состоит в том, чтобы предоставить программному коду доступ к внутренностям механизма выполнения через интерфейсы прикладного программирования (API) как это для .СЕТЬ IL эмиттер.
  2. Второй подход - это динамическое выполнение выражений, которые содержат команды программирования, часто составленные из строк, но также могут исходить из других методов, использующих аргументы или контекст, например Javascript.[6] Таким образом, «программы могут писать программы». Хотя оба подхода могут использоваться в одном и том же языке, большинство языков склоняются к одному или другому.
  3. Третий подход - полностью выйти за пределы языка. Общее назначение преобразование программы такие системы, как компиляторы, которые принимают описания языков и выполняют произвольные преобразования на этих языках, являются прямыми реализациями общего метапрограммирования. Это позволяет применять метапрограммирование практически к любому целевому языку независимо от того, обладает ли этот целевой язык собственными способностями к метапрограммированию. Это можно увидеть при работе с Схема и как это позволяет преодолеть некоторые ограничения, с которыми C с помощью конструкций, которые были частью самого языка Scheme для расширения C.[7]

Лисп вероятно, наиболее существенный язык с возможностями метапрограммирования, как из-за его исторического преимущества, так и из-за простоты и мощности его метапрограммирования. В метапрограммировании Лиспа оператор отмены кавычек (обычно запятая) вводит код, который оценивается во время определения программы, а не во время выполнения; видеть Самооценка форм и цитирование в Лиспе. Таким образом, язык метапрограммирования идентичен основному языку программирования, а существующие процедуры Lisp при желании могут быть напрямую повторно использованы для метапрограммирования. Этот подход был реализован на других языках путем включения в программу интерпретатора, который работает непосредственно с данными программы. Существуют реализации такого рода для некоторых распространенных языков высокого уровня, таких как RemObjectsСкрипт Паскаля за Object Pascal.


Использование

Генерация кода

Вот простой пример метапрограммы. Оболочка POSIX сценарий, который является примером генеративное программирование:

#! / bin / sh# метапрограммаэхо '#! / bin / sh' > программаза я в $(seq 992)делать    эхо "эхо $ i" >> программасделанопрограмма chmod + x

Этот сценарий (или программа) генерирует новую программу из 993 строк, которая выводит числа 1–992. Это только иллюстрация того, как использовать код для написания большего количества кода; это не самый эффективный способ распечатать список чисел. Тем не менее, программист может написать и выполнить эту метапрограмму менее чем за минуту и ​​за это время сгенерирует более 1000 строк кода.

А лоза - это особый вид метапрограммы, который на выходе создает собственный исходный код. Квайны обычно представляют только развлекательный или теоретический интерес.

Не все метапрограммирование включает в себя генеративное программирование. Если программы можно изменять во время выполнения или доступна инкрементная компиляция (например, в C #, Четвертый, Фринк, Groovy, JavaScript, Лисп, Эликсир, Lua, Perl, PHP, Python, REBOL, Рубин, Ржавчина, SAS, Болтовня, и Tcl ), то можно использовать методы для выполнения метапрограммирования без фактического создания исходного кода.

Один из стилей генеративного подхода - использовать предметно-ориентированные языки (DSL). Довольно распространенный пример использования DSL включает в себя генеративное метапрограммирование: lex и yacc, два инструмента, используемых для создания лексические анализаторы и парсеры, позвольте пользователю описать язык, используя обычные выражения и контекстно-свободные грамматики, и встроить сложные алгоритмы, необходимые для эффективного синтаксического анализа языка.

Инструментарий кода

Одно из применений метапрограммирования - это инструментальные программы для выполнения динамический анализ программы.

Изменения в поведении

Метапрограммирование может использоваться для внесения поведенческих изменений в программу, как это сделано в аспектно-ориентированное программирование. Например, метапрограммирование можно использовать для внедрения флаги функций или изучить возможные патчи для исправления ошибок.[8]

Вызовы

Некоторые утверждают, что для полноценного использования функций метапрограммирования требуется резкая кривая обучения.[9] Поскольку метапрограммирование дает большую гибкость и настраиваемость во время выполнения, неправильное использование или неправильное использование метапрограммирования может привести к неоправданным и неожиданным ошибкам, отладку которых для среднего разработчика может быть чрезвычайно сложно. Он может внести риски в систему и сделать ее более уязвимой, если не использовать ее с осторожностью. Некоторые из распространенных проблем, которые могут возникнуть из-за неправильного использования метапрограммирования, - это неспособность компилятора идентифицировать отсутствующие параметры конфигурации, недопустимые или неверные данные могут привести к неизвестному исключению или другим результатам.[10] Из-за этого некоторые считают[9] что только высококвалифицированные разработчики должны работать над разработкой функций, которые осуществляют метапрограммирование на языке или платформе, а средние разработчики должны научиться использовать эти функции как часть соглашения.

Использование в языках программирования

Макросистемы

Макроассемблеры

В IBM / 360 и деривативы имели мощные макроассемблер объекты, которые часто использовались для создания полных язык ассемблера программы[нужна цитата ] или разделы программ (например, для разных операционных систем). Макросы, поставляемые с CICS обработка транзакции В системе были макросы ассемблера, которые генерировали операторы COBOL в качестве шага предварительной обработки.

Другие ассемблеры, такие как MASM, также поддерживают макросы.

Метаклассы

Метаклассы предоставляются следующими языками программирования:

Метапрограммирование шаблона

Поэтапное метапрограммирование

Зависимые типы

Использование зависимые типы позволяет доказать, что сгенерированный код никогда не является недействительным.[15] Однако этот подход является передовым и редко встречается за пределами исследовательских языков программирования.

Реализации

Список известных систем метапрограммирования поддерживается на Список систем трансформации программ.

Смотрите также

Рекомендации

  1. ^ Харальд Сондергаард. «Курс по анализу и трансформации программ». Получено 18 сентября 2014.
  2. ^ Чарнецкий, Кшиштоф; Эйзенекер, Ульрих В. (2000). Генеративное программирование. ISBN  0-201-30977-7.
  3. ^ Уокер, Макс. «Искусство метапрограммирования на Java». Новый круг. Получено 28 января 2014.
  4. ^ Краусс, Аарон. "Концепции программирования: самоанализ и размышление о типах". Общество. Получено 14 сентября 2014.
  5. ^ Джоши, Пратик. «Что такое метапрограммирование? - Часть 2/2». Вечная загадка. Получено 14 августа 2014.
  6. ^ например instance_eval в Рубин принимает строку или анонимную функцию. «Rdoc для класса: BasicObject (Ruby 1.9.3) - instance_eval». Получено 30 декабря 2011.
  7. ^ «Искусство метапрограммирования».
  8. ^ Дюрье, Томас; Корню, Бенуа; Сейнтюрье, Лайонел; Монперрус, Мартин (2017). «Генерация динамического патча для исключений с нулевым указателем с использованием метапрограммирования» (PDF). 24-я Международная конференция по анализу, эволюции и реинжинирингу программного обеспечения, IEEE, 2017 (SANER). IEEE: 349–358. Дои:10.1109 / SANER.2017.7884635. ISBN  978-1-5090-5501-2.
  9. ^ а б Бикинг, Ян. «Проблема метапрограммирования». IanBicking.org. Получено 21 сентября 2016.
  10. ^ Терри, Мэтт. «Остерегайтесь метапрограммирования». Medium.com. Средняя корпорация. Получено 21 августа 2014.
  11. ^ Через Общая объектная система Lisp "Протокол метаобъектов"
  12. ^ Лисп (язык программирования) «Самооценочные формы и цитирование», оператор квазицикции.
  13. ^ «LMS: создание программ и встроенные компиляторы в Scala». scala-lms.github.io. Получено 2017-12-06.
  14. ^ Rompf, Tiark; Одерский, Мартин (июнь 2012). «Облегченная модульная постановка: прагматический подход к генерации кода времени выполнения и скомпилированным DSL». Commun. ACM. 55 (6): 121–130. Дои:10.1145/2184319.2184345. ISSN  0001-0782.
  15. ^ Хлипала, Адам (июнь 2010 г.). "Ur: статически типизированное метапрограммирование с вычислением записей на уровне типа" (PDF). Уведомления ACM SIGPLAN. PLDI '10. 45 (6): 122–133. Дои:10.1145/1809028.1806612. Получено 29 августа 2012.

внешняя ссылка