Что такое свободные и связанные переменные?

Я программировал долгое время (на самом деле слишком долго), но я действительно изо всех сил пытаюсь понять термины "Свободные переменные" и "Связанные переменные".

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

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

2 ответа

Свободная переменная - это переменная, используемая в некоторой функции, значение которой зависит от контекста, в котором функция вызывается, вызывается или используется. Например, в математических терминах, z является свободной переменной, потому что не ограничен никаким параметром. x является ограниченной переменной:

f(x) = x * z

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

Оценка ограниченной переменной не зависит от контекста вызова функции. Это самый распространенный в современных языках программирования тип переменных. Локальные переменные, глобальные переменные и параметры - это ограниченные переменные.

Свободная переменная в некотором роде похожа на соглашение " передача по имени " некоторых древних языков программирования.

Допустим, у вас есть функция f это просто печатает некоторую переменную:

def f():
    print(X)

Это Питон. В то время как X не является локальной переменной, ее значение соответствует соглашению Python: она ищет вверх по цепочке блоков, где определена функция, пока не достигнет модуля верхнего уровня.

Так как в Python значение X определяется контекстом объявления функции, мы говорим, что X является ограниченной переменной.

Гипотетически, если X были свободной переменной, это должно вывести 10:

X = 2

def f():
    print(X)

def g():
    # X is a local variable to g, shadowing the global X
    X = 10
    f()

В Python этот код печатает 2, потому что оба X переменные ограничены. Местный X переменная на g ограничен как локальная переменная, а f ограничен глобальным X,

Реализация

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

Значение свободной переменной обычно не может быть определено во время компиляции, так как сильно определяется потоком времени выполнения и стеком вызовов.

Является ли переменная свободной или связанной, относительна; это зависит от фрагмента кода, который вы просматриваете.

В этом фрагменте х связан:

function(x) {return x + x;};

И здесь x происходит бесплатно:

return x + x;

Другими словами, свобода является свойством контекста. Вы не говорите "x является свободной переменной" или "x является связанной переменной", но вместо этого определяете контекст, о котором говорите: "x свободен в выражении E". По этой причине одна и та же переменная x может быть либо свободной, либо связанной, в зависимости от того, о каком фрагменте кода вы говорите. Если фрагмент содержит сайт привязки переменной (например, он указан в аргументах функции), то он связан, если нет, то он свободен.

Где различие между свободным и связанным важно с точки зрения реализации, когда вы реализуете, как работает подстановка переменных (например, что происходит, когда вы применяете аргументы к функции.) Рассмотрите этапы оценки:

(function(x) {return x + x;})(3);
=> 3 + 3
=> 6

Это работает нормально, потому что x свободен в теле функции. Однако, если x был связан в теле функции, наша оценка должна быть осторожной:

(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return x * 2;})(3 + 3); // careful to leave this x alone for now!
=> (function(x){return x * 2;})(6);
=> 6 * 2
=> 12

Если бы наша реализация не проверяла наличие вхождений, она могла бы заменить ограничение x для 3 и дал нам неправильный ответ:

(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return 3 * 2;})(3 + 3); // Bad! We substituted for a bound x!
=> (function(x){return 3 * 2;})(6);
=> 3 * 2
=> 6

Также следует уточнить, что free vs. bound является свойством синтаксиса (то есть самого кода), а не свойством того, как код оценивается во время выполнения. vz0 говорит о динамически изменяемых переменных, которые в некоторой степени связаны со свободными переменными, но не синонимичны с ними. Как правильно описывает vz0, область динамических переменных - это языковая функция, которая позволяет оценивать выражения, содержащие свободные переменные, просматривая стек вызовов во время выполнения, чтобы найти значение переменной с таким же именем. Однако все же имеет смысл говорить о свободных вхождениях переменных в языках, которые не допускают динамическую область видимости: вы просто получите ошибку (например, "x не определен"), если попытаетесь оценить такое выражение в этих языки.

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

Другие вопросы по тегам