Что такое метапрограммирование?

129

Я читал статью на TheServerSide о программировании плойглотов на платформе Java . Некоторые комментарии в статье относятся к метапрограммированию как к способности генерировать код (возможно, «на лету»).

Метапрограммирование способности генерировать код на лету или способность внедрять методы и атрибуты в существующие объекты во время выполнения (например, то, что позволяют некоторые динамические языки, такие как Python, Ruby и Groovy).

Параг
источник
7
Возможно, вам будет интересен этот ответ stackoverflow.com/questions/2565572/…
ewernli
@ewernli: Этот ответ на самом деле лучше, чем любой из ответов здесь!
JD

Ответы:

101

Метапрограммирование относится к множеству способов, которыми программа познает себя или может управлять собой.

В таких языках, как C #, отражение - это форма метапрограммирования, поскольку программа может исследовать информацию о себе. Например, возврат списка всех свойств объекта.

В таких языках, как ActionScript, вы можете оценивать функции во время выполнения для создания новых программ, таких как eval ("x" + i). DoSomething () повлияет на объект с именем x1, когда i равен 1, и x2, когда i равен 2.

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

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

Из эссе Пола Грэма «Что сделало Лисп другим» :

Во многих языках есть то, что называется макросом. Но макросы Lisp уникальны. И, хотите верьте, хотите нет, но то, что они делают, связано со скобками. Разработчики Lisp не поместили все эти скобки в язык просто для того, чтобы отличаться. Программисту Blub код на Лиспе кажется странным. Но эти скобки не зря. Они являются очевидным свидетельством фундаментального различия Лиспа и других языков.

Код на Лиспе состоит из объектов данных Лиспа. И не в том банальном смысле, что исходные файлы содержат символы, а строки являются одним из типов данных, поддерживаемых языком. Код Лиспа после того, как он прочитан синтаксическим анализатором, состоит из структур данных, которые вы можете перемещать.

Если вы понимаете, как работают компиляторы, то на самом деле происходит не столько то, что Лисп имеет странный синтаксис, сколько то, что Лисп не имеет синтаксиса. Вы пишете программы в деревьях синтаксического анализа, которые генерируются в компиляторе при синтаксическом анализе других языков. Но эти деревья синтаксического анализа полностью доступны для ваших программ. Вы можете писать программы, которые ими управляют. В Лиспе эти программы называются макросами. Это программы, которые пишут программы.

Программы, пишущие программы? Когда бы вы когда-нибудь захотели это сделать? Не очень часто, если подумать на Коболе. Все время, если думать на Лиспе. Было бы удобно, если бы я мог привести пример мощного макроса и сказать там! как насчет этого? Но если бы я это сделал, это было бы просто тарабарщиной для человека, не знающего Лисп; здесь нет места, чтобы объяснить все, что вам нужно знать, чтобы понять, что это значит. В Ansi Common Lisp я старался продвигать вещи так быстро, как мог, и даже в этом случае я не дошел до макросов до страницы 160.

Но я думаю, что могу привести доводы, которые могут быть убедительными. Исходный код редактора Viaweb, вероятно, состоял примерно на 20-25% из макросов. Макросы сложнее писать, чем обычные функции Лиспа, и считается плохим стилем использовать их, когда они не нужны. Таким образом, каждый макрос в этом коде присутствует потому, что должен быть. Это означает, что по крайней мере 20-25% кода в этой программе выполняет то, что вы не можете легко сделать на любом другом языке. Каким бы скептиком ни относился программист Blub к моим утверждениям о таинственных способностях Lisp, это должно вызвать у него любопытство. Мы писали этот код не для собственного развлечения. Мы были крохотным стартапом и программировали изо всех сил, чтобы создать технические барьеры между нами и нашими конкурентами.

Подозрительный человек может задаться вопросом, есть ли здесь какая-то корреляция. Большая часть нашего кода выполняла вещи, которые очень трудно сделать на других языках. Получившееся программное обеспечение делало то, чего не могли делать программы наших конкурентов. Может, была какая-то связь. Я призываю вас следовать этой теме. В этом старике, ковыляющем на костылях, может быть больше, чем кажется на первый взгляд.

DavGarcia
источник
6
Не забывайте о метапрограммировании шаблонов в C ++. Возможность выполнять выражения и принимать решения во время компиляции, а также статически компилировать результаты в окончательный исполняемый файл.
Реми Лебо
1
Я был шокирован, in order to put technical barriers between us and our competitorsи это тамаде правильно.
Эван Ху
4
Программы, которые манипулируют собой, являются подмножеством всех метапрограмм. Метапрограммирование вообще означает программы, которые манипулируют программами.
JD
55

Отличный вопрос. Мне очень жаль, что ни один из ответов в настоящее время не отвечает на ваш вопрос правильно. Возможно, я смогу помочь ...

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

Ваш принятый ответ говорит о программах, которые манипулируют собой. Это действительно метапрограммы, но они являются подмножеством всех метапрограмм.

Все:

  • Парсеры
  • Языки, специфичные для домена (DSL)
  • Встроенные доменные языки (EDSL)
  • Составители
  • интерпретаторы
  • Редакторы терминов
  • Средства доказательства теорем

метапрограммы. Итак, компилятор GCC - это метапрограмма, интерпретатор CPython - это метапрограмма, система компьютерной алгебры Mathematica - это метапрограмма, средство доказательства теорем Coq - это метапрограмма и так далее.

В других ответах утверждалось, что метапрограммы - это программы, которые генерируют другие программы. Это действительно метапрограммы, но, опять же, они являются подмножеством всех метапрограмм. Библиотека самого быстрого преобразования Фурье на Западе (FFTW) является примером такой метапрограммы. Исходный код написан в основном на OCaml и генерирует биты кода C (называемые кодлетами), которые объединяются для создания высокопроизводительных подпрограмм быстрого преобразования Фурье , оптимизированных для конкретных машин. Эта библиотека фактически используется для обеспечения подпрограмм БПФ в Matlab. Люди пишут программы для генерации численных методов на протяжении десятилетий, с первых дней FORTRAN .

Первым языком программирования, который интегрировал поддержку метапрограммирования, был язык LISt Processor (LISP) в конце 1950-х годов. LISP 1.5 включает ряд функций, упрощающих метапрограммирование. Во-первых, основной тип данных LISP - это вложенные списки, т. Е. Подобные деревья (a (b c) d), что означает, что любой код LISP может быть изначально выражен как структура данных. Это известно как гомоиконность. Во-вторых, код LISP можно легко преобразовать в данные с помощью QUOTE. Например, (+ 1 2 3)складывает 1 + 2 + 3 и (QUOTE (+ 1 2 3))создает выражение, которое добавляет 1 + 2 + 3 при оценке. В-третьих, LISP предоставил мета-циклический анализатор, который позволяет вам использовать интерпретатор или компилятор хоста для оценки кода LISP во время выполнения, включая код LISP, сгенерированный во время выполнения. Потомки LISP включают Scheme и Clojure, Во всех этих языках метапрограммирование чаще всего встречается в форме программ, которые изменяют себя, обычно с использованием макросов.

В 1970-х Робин Милнер разработал MetaLanguage (ML), который превратился в семейство языков программирования ML, которое включает Standard ML и OCaml и сильно повлияло на Haskell и F # . Эти языки позволяют легко выражать другие языки. В этих языках метапрограммы чаще всего встречаются в форме лексеров, синтаксических анализаторов, интерпретаторов и компиляторов.

В 1994 году Эрвин Унру обнаружил, что система шаблонов C ++ завершена по Тьюрингу и может использоваться для выполнения произвольных программ во время компиляции . Метапрограммирование шаблонов C ++ принесло метапрограммирование немытым массам, которые (ab) использовали его для множества разных целей, включая создание численных методов в библиотеке Blitz ++ .

JD
источник
33

Что ж, метапрограммирование - это просто программирование, но в основном это «написание кода, который пишет код» .

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

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

В языках со статической типизацией также есть мощные методы метапрограммирования, например метапрограммирование шаблона C ++ ...

CMS
источник
14

Это всего лишь мое личное мнение, которое, вероятно, является наиболее либеральным определением метапрограммирования.

Думаю, сюда входят:

  1. Генерация кода компиляции или генерация кода времени выполнения (или оба)
  2. Аспектно-ориентированное мышление или аспектно-ориентированное программирование
  3. СУХОЕ мышление

Я думаю, вы можете достичь этого, используя любое из них и в сочетании:

  1. отражение
  2. DSL (доменные языки)
  3. Атрибуты (.NET) или аннотации (Java)
  4. Дженерики (.NET / Java)
  5. Шаблоны (C ++)
  6. method_missing (Рубин)
  7. закрытие / функции первого класса / делегаты
  8. АОП - аспектно-ориентированное программирование
BuddyJoe
источник
очень лаконичный и вдумчивый ответ. дал мне хороший список вещей для исследования. Спасибо!
swyx
6

Метапрограммирование - это написание программы, которая выводит другую программу. В этом действительно хороши языки вроде Lisp. Это намного проще сделать на языке, который поддерживает настоящие макросы (не макросы C ++, а скорее те, которые могут манипулировать кодом, который они выводят), например Ruby, Lisp, Scheme и т. Д., Чем на таком языке, как Java.

Одна реализация заключается в создании «предметно-ориентированного языка», который является способом улучшения языка программирования для выполнения конкретной задачи. Если все сделано правильно, это может быть невероятно мощным. Ruby on Rails - хороший пример такого рода программирования.

Если вы заинтересованы в изучении этого метода, посмотрите « Структура и интерпретация компьютерных программ», которая является одной из основополагающих книг по этой теме.

Стив Роу
источник
5

Метапрограммирование - это написание компьютерных программ, которые пишут или манипулируют другими программами (или самими собой) как своими данными, или которые выполняют часть работы во время выполнения, которая в противном случае выполнялась бы во время компиляции. Во многих случаях это позволяет программистам делать больше за то же время, которое им потребовалось бы для написания всего кода вручную, или дает программам большую гибкость для эффективной обработки новых ситуаций без перекомпиляции. ( Источник .)

По сути, это написание кода, который выводит больше кода, который запускается для достижения какой-то цели. Обычно это делается либо на том же языке (используя javascript для создания строки javascript, затем evalее), либо для вывода на другом языке (используя .NET для создания командного файла Windows).

EndangeredMassa
источник
4

В Википедии есть хорошая статья по этой теме. Чтобы что-то квалифицировалось как метапрограммирование, не нужно вносить изменения во время выполнения. Например, многие люди используют шаблоны C ++ для метапрограммирования во время компиляции.

Г-н Фуз
источник