Ви отримали кілька хороших відповідей поки що; дозвольте навести вам непрактичний, але високоосвічений приклад того, як ви могли б спроектувати мову без поняття стеки чи «контрольного потоку». Ось програма, яка визначає фактичні факти:
function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = f(3)
Ми ставимо цю програму в рядок і оцінюємо програму за текстовою підстановою. Отже, коли ми проводимо оцінку f(3)
, ми робимо пошук і замінюємо 3 на i, наприклад:
function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = if 3 == 0 then 1 else 3 * f(3 - 1)
Чудово. Тепер ми виконуємо ще одну підстановку тексту: ми бачимо, що умова "якщо" - хибне, і замінюємо інший рядок, виробляючи програму:
function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = 3 * f(3 - 1)
Тепер ми робимо ще одну заміну рядків для всіх підвиразів, що включають константи:
function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = 3 * f(2)
І ви бачите, як це йде; Я не буду більше працювати. Ми могли б продовжувати робити ряд підстановок, поки не дійшли до let x = 6
нас, і ми не закінчилися
Ми використовуємо стек традиційно для локальних змінних та інформації про продовження; Пам'ятайте, стек не говорить вам, звідки ви прийшли, він говорить вам, куди ви йдете далі, з цією поверненою вартістю в руці.
У моделі підстановки рядків програмування на стеці немає "локальних змінних"; формальні параметри замінюються на їх значення, коли функція застосовується до її аргументу, а не поміщається в таблицю пошуку на стеці. І немає "йти кудись далі", тому що оцінювання програми - це просто застосування простих правил підстановки рядків для створення іншої, але еквівалентної програми.
Звичайно, насправді робити заміну рядків - це, мабуть, не шлях. Але мови програмування, які підтримують «екваціональне міркування» (наприклад, Haskell), логічно використовують цю методику.