Что такое поэтапные функции (концептуально)?


24

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

Они дают краткое объяснение (выделено мое и номер ссылки изменен; в оригинале 22)

В контексте генерации программ, многоступенчатое программирование (MSP, сокращенное использование), как установлено Taha и Sheard [2], позволяет программистам явно откладывать оценку выражения программы на более позднюю стадию (таким образом, ставить выражение). Настоящий этап эффективно действует как генератор кода, который составляет (и, возможно, выполняет) программу следующего этапа.

Однако Таха и Шеард пишут (выделение мое):

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

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

Эти утверждения кажутся ортогональными, если не противоречивыми; может быть, то, что пишут Ромпф и Одерский, является приложением того, что предлагают Таха и Шеард, но, возможно, это другой взгляд на то же самое. Кажется, они согласны с тем, что важным моментом является то, что программы (пере) пишут свои части во время выполнения, но я не знаю, является ли это необходимой и / или достаточной способностью.

Итак, что такое постановка, соответственно, интерпретации постановки в этом контексте? Откуда этот термин?


  1. Облегченная модульная организация: прагматический подход к генерации кода времени выполнения и скомпилированным DSL Т. Ромпфом и М. Одерским (2012)
  2. MetaML и многоэтапное программирование с явными аннотациями W. Taha и T. Sheard (2000)

Какое противоречие вы видите между двумя утверждениями? Мне кажется, они говорят об одном и том же, с разным акцентом.
Жиль "ТАК - прекрати быть злым"

@ Жиль: мне не нужна генерация / компиляция кода во время выполнения, чтобы отложить оценку чего-либо (см. Продолжение). Вполне возможно, что это просто еще один акцент (я допускаю этот вариант в вопросе), но я не могу сказать точно.
Рафаэль

Вы можете ознакомиться с документацией по реализации и метапрограммированию языка программирования Julia на сайте @generated functions: julia.readthedocs.org/en/latest/manual/metaprogramming/…
SalchiPapa

Ответы:


21

Насколько мне известно, термин поэтапное вычисление впервые был использован Биллом Шерлисом в этой статье . До этого термин « частичная оценка » использовался для почти одного и того же понятия, но идея поэтапного вычисления несколько отличается. Обе идеи связаны с теоремой Клини о Смне .

Если у вас есть функция из двух аргументов, но вы знаете один аргумент, скажем, , то вы можете выполнить некоторые вычисления функции сразу, используя знания первого аргумента. Затем вам остается функция , вычисления которой зависят только от второго, неизвестного аргумента.m ϕ m ( n )ϕ(m,n)mϕm(n)

Идея частичной оценки заключается в автоматическом вычислении специализированной функции . Учитывая код для исходной функции , частичная оценка выполняет статический анализ, чтобы определить, какие биты кода зависят от а какие биты зависят от , и преобразовывает его в функцию которая, учитывая , . Затем второй аргумент может быть передан этой специализированной функции.φ м п φ ' м φ м пϕm(n) ϕmnϕmϕmn

Идея поэтапного вычисления заключается в том, чтобы сначала подумать о функции . Это называется «поэтапной» функцией, потому что она работает в несколько этапов. Как только мы передадим ему первый аргумент , он код для специализированной функции . Это «первый этап». На втором этапе второй аргумент предоставляется который выполняет остальную часть работы. m ϕ m ϕ mϕmϕmϕm

Итак, задача частичной оценки - преобразовать код для обычной функции в поэтапную функцию . Шерлис предполагал, что это преобразование может быть выполнено с помощью более общих механизмов, чем более ранние методы частичной оценки. Предмет «поэтапного вычисления» теперь имеет дело с такими вопросами, как:ϕ ϕϕ

  • Как определить поэтапные функции?
  • Какие языки программирования и системы типов следует использовать для определения поэтапных функций?
  • Какова семантика таких языков?
  • Как мы обеспечиваем согласованность и правильность поставленных функций?
  • Какие методы полезны для автоматического или полуавтоматического построения поэтапных функций?
  • Как мы докажем правильность таких приемов?

Постепенное вычисление может быть очень важным на практике. Фактически, каждый компилятор является поэтапным вычислением. Исходя из исходной программы, она создает переведенную и оптимизированную целевую программу, которая затем может взять фактические данные и вычислить результат. На практике сложно написать поэтапные вычислительные программы, потому что нам приходится совмещать несколько этапов и следить за тем, чтобы правильные действия выполнялись в нужное время. Все, кто написал компилятор, боролись с такими проблемами. Также трудно писать программы, которые пишут другие программы, могут ли они быть программами на машинном языке (компиляторы), запросами SQL (манипуляции с базой данных) или кодом HTML / Server Pages / Javascript (веб-приложения) и множеством других приложений.


ϕϕ

Таким образом, вы имеете в виду, что частичная оценка - это абстракция над многоступенчатым программированием, то есть частичное вычисление не подразумевает многоступенчатое программирование, а многоступенчатое программирование подразумевает частичное вычисление. При этом частичное вычисление может быть выполнено в один или несколько этапов, поскольку каррирование в функциональных языках не обязательно включает в себя несколько этапов и генерацию кода во время выполнения, верно?
denis631

1
Не совсем. Частичный оценщик компилирует обычную программу в двухэтапную программу, а затем запускает ее первый этап. В поэтапном программировании вы пишете многоэтапную программу самостоятельно.
Uday Reddy

9

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

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

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

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

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

См. «Генеративное программирование» Чарнецкого и Эйзенекера (ISBN-13: 978-0201309775).


@ Рафаэль: Вот третья глава с основами доменов и повторного использования. Посмотрите даже на упомянутую оптимизацию. БПФ не делается путем постановки, чтобы заставить его работать быстрее. Это сделано для того, чтобы программисту не приходилось каждый раз вручную вычислять таблицу значений, копировать их в программу и создавать большой список. Это минимизировать проделанную работу и повторно использовать основные этапы. То же самое с развертыванием цикла. Выполнение этого вручную повторяет информацию и не может быть повторно использовано.
ex0du5

Эта точка зрения DSL, по-видимому, ограничивает промежуточное размещение одним уровнем (один DSL-компилятор внутри программы), верно?
Рафаэль

1
@ Рафаэль: Это действительно зависит от вашей точки зрения. Очевидно, что эта концепция не добавляет вычислительной мощности, если рассматривать ее просто как исходный текст -> исполняемый перевод. Мы могли бы просто создать компилятор для языка DS и покончить. Откуда исходит сила, так это в итерации. При создании библиотек, которые будут использоваться и расширяться проектами в будущем, естественные стадии появляются внутри границ библиотеки. У вас может быть библиотека, которая преобразует спецификации объекта в исходный код для полной сериализации, а затем другая библиотека, которая создает транспортный уровень, построенный на некоторой спецификации диспетчеризации ...
ex0du5

1
@ Рафаэль: Постановка может быть более естественным делом в несколько этапов. Если у одного куска кода его требования со временем сильно меняются, а другие более стабильны, может быть целесообразно из-за «разделенных слоев» разделить этапы на уровни с более стабильными интерфейсами. Затем вы можете влиять на меньшую часть системы с изменениями и соблюдать промежуточную форму принципа открытого-закрытого. Это практические проблемы, которые не имеют математической необходимости, но все это основано на практичности. Нам не нужен ни один язык компилятора, мы хотим допустить эволюцию.
ex0du5

5

Ответ дается в технической перспективе для рассматриваемой статьи [1]. Рассматриваемая проблема - это область напряженности между общим и конкретным кодом:

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

Конечно, мы хотим устранить эту напряженность, то есть достичь общего кода и конкретной реализации:

Мы можем задать вопрос: возможно ли написать код так, чтобы он был универсальным, но затем он автоматически специализировался на ситуации, возникающей во время выполнения?

Это породило идею о том, что (общие) программы (пере) пишут сами во время выполнения, чтобы приспособиться к конкретной ситуации:

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

Я думаю, JIT Java является хорошим примером. Одна конкретная идея - многоступенчатое программирование, которое Ли объясняет так:

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

Таким образом, «постановка» - это способ просмотра подходящих функций / кода, который идентифицирует фазы вычисления / выполнения, которые можно упростить, зная результаты предыдущих фаз. «Задержка» вычислений, как в первой цитате в вопросе, может быть необходимым побочным эффектом для правильного разделения этапов, но это не главное.

Ромпф и Одерский упоминают быстрое преобразование Фурье в качестве примера, который может быть поучительным.


  1. Лиса и еж: техническая перспектива Питера Ли (2012)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.