stringtranslate.com

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

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

Метапрограммирование можно использовать для перемещения вычислений из времени выполнения во время компиляции , для генерации кода с использованием вычислений во время компиляции и для включения самомодифицирующегося кода . Способность языка программирования быть собственным метаязыком называется рефлексией . [4] Рефлексия — ценная функция языка, облегчающая метапрограммирование.

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

Подходы

Метапрограммирование позволяет разработчикам писать программы и разрабатывать код, который подпадает под общую парадигму программирования . Наличие самого языка программирования как первоклассного типа данных (как в Lisp , Prolog , SNOBOL или Rebol ) также очень полезно; это известно как гомоиконичность . Общее программирование задействует средства метапрограммирования внутри языка, позволяя писать код, не заботясь об указании типов данных, поскольку при использовании они могут быть предоставлены в качестве параметров .

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

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

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

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

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

Простым примером метапрограммы является этот сценарий POSIX Shell , который является примером генеративного программирования :

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

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

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

Не все метапрограммирование включает в себя генеративное программирование. Если программы можно изменять во время выполнения или доступна инкрементальная компиляция (например, в C# , Forth , Frink , Groovy , JavaScript , Lisp , Elixir , Lua , Nim , Perl , PHP , Python , REBOL , Ruby , Rust , SAS , Smalltalk , и Tcl ), тогда можно использовать методы метапрограммирования без фактического создания исходного кода.

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

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

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

Проблемы

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

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

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

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

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

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

Метаклассы

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

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

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

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

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

Реализации

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

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

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

  1. ^ Харальд Зондергаард. «Курс программного анализа и трансформации» . Проверено 18 сентября 2014 г.
  2. ^ Чарнецкий, Кшиштоф ; Эйзенекер, Ульрих В. (2000). Генеративное программирование . ISBN 0-201-30977-7.
  3. ^ Уокер, Макс. «Искусство метапрограммирования на Java». Новый круг . Проверено 28 января 2014 г.
  4. ^ Краусс, Аарон. «Концепции программирования: самоанализ и рефлексия типов». Общество . Проверено 14 сентября 2014 г.
  5. Джоши, Пратик (5 апреля 2014 г.). «Что такое метапрограммирование? - Часть 2/2». Вечная загадка . Проверено 14 августа 2014 г.
  6. ^ например, example_eval в Ruby принимает строку или анонимную функцию. «Rdoc для класса: BasicObject (Ruby 1.9.3) — instance_eval» . Проверено 30 декабря 2011 г.
  7. ^ «Искусство метапрограммирования». ИБМ .
  8. ^ аб Бикинг, Ян. «Задача метапрограммирования». IanBicking.org . Проверено 21 сентября 2016 г.
  9. Терри, Мэтт (21 августа 2013 г.). «Остерегайтесь метапрограммирования». Medium.com . Средняя корпорация . Проверено 21 августа 2014 г.
  10. ^ Через «Протокол метаобъектов» Common Lisp Object System.
  11. ^ «Метапрограммирование шаблонов C ++» . aszt.inf.elte.hu. _ Проверено 23 июля 2022 г.
  12. ^ Lisp (язык программирования) «Самовычисляемые формы и цитирование», оператор квазикавычек.
  13. ^ «LMS: генерация программ и встроенные компиляторы в Scala». scala-lms.github.io . Проверено 6 декабря 2017 г.
  14. ^ Ромпф, Тиарк; Одерский, Мартин (июнь 2012 г.). «Облегченная модульная подготовка: прагматичный подход к генерации кода во время выполнения и скомпилированным DSL». Коммун. АКМ . 55 (6): 121–130. дои : 10.1145/2184319.2184345. ISSN  0001-0782. S2CID  52898203.
  15. ^ Члипала, Адам (июнь 2010 г.). «Ур: статически типизированное метапрограммирование с вычислением записей на уровне типа» (PDF) . Уведомления ACM SIGPLAN . ПЛДИ '10. 45 (6): 122–133. дои : 10.1145/1809028.1806612 . Проверено 29 августа 2012 г.

Внешние ссылки