stringtranslate.com

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

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

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

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

Подходы

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

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

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

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

Обычаи

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

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

#!/bin/sh # метапрограмма echo '#!/bin/sh' > программа for i in $( 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 , R , SAS , Smalltalk и Tcl ), то можно использовать методы для выполнения метапрограммирования без генерации исходного кода.

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

Кодовая аппаратура

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

Вызовы

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

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

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

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

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

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

Метаклассы

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

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

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

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

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

Реализации

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

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

Ссылки

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

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

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