Преобразователь


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

Термин возник как причудливая неправильная форма глагола думать . Это относится к первоначальному использованию thunks в компиляторах ALGOL 60 , что требовало специального анализа (мысли), чтобы определить, какой тип подпрограммы генерировать. [1] [2]

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

Простая реализация «вызова по имени» может заменить код выражения аргумента для каждого появления соответствующего параметра в подпрограмме, но это может создать несколько версий подпрограммы и несколько копий кода выражения. В качестве улучшения компилятор может сгенерировать вспомогательную подпрограмму, называемую thunk , которая вычисляет значение аргумента. Затем адрес и окружение [a] этой вспомогательной подпрограммы передаются исходной подпрограмме вместо исходного аргумента, откуда ее можно вызывать столько раз, сколько необходимо. Питер Ингерман впервые описал преобразователи применительно к языку программирования ALGOL 60, который поддерживает вычисление вызовов по имени. [4]

Хотя индустрия программного обеспечения в значительной степени стандартизировала оценку вызова по значению и вызову по ссылке , [5] активное изучение вызова по имени продолжалось в сообществе функционального программирования . В результате этого исследования была создана серия языков программирования для ленивых вычислений , в которых некоторый вариант вызова по имени является стандартной стратегией вычисления. Компиляторы для этих языков, такие как Glasgow Haskell Compiler , в значительной степени полагались на преобразователи с добавленной функцией, заключающейся в том, что преобразователи сохраняют свой первоначальный результат, чтобы избежать его повторного вычисления; [6] это известно как запоминание или вызов по необходимости .

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