Thunk


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

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

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

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

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

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