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

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

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

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

Ответы

Ответ 1

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

f(x) = x * z

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

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

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

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

def f():
    print(X)

Это Python. Хотя 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.

Реализация

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

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

Ответ 2

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

В этом фрагменте 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 свободен в теле функции. Однако, если х было связано в теле функции, наша оценка должна быть осторожной:

(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 не определено" ), если вы попытаетесь оценить такое выражение в этих языки.

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