Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Самое простое объяснение термина "замыкание"

9 views
Skip to first unread message

Ilia Tarasov

unread,
Jul 25, 2007, 4:08:15 AM7/25/07
to
Hi All,

Собственно, вот! :)

Действительно проблема. Я понимаю, что математическая культура, техника в
руках дикаря, голова должна быть и так далее :) Hо цель не отсепарировать
математиков, а дать _простое_ объяснение, "на пальцах". Чтобы было понятно и
человеку, который является специалистом (!) в другой области. Пока что попытка
обсудить методологию приводила в основном к флейму... Определения есть, не в
этом дело. Требуется корректное "вхождение в проблему", чтобы стало понятно не
только, как оно делается, но и зачем.

bye

Miguel Mitrofanov

unread,
Jul 25, 2007, 5:27:38 AM7/25/07
to
Hello, Ilia! You wrote:

IT> Действительно проблема. Я понимаю, что математическая культура,
IT> техника в руках дикаря, голова должна быть и так далее :) Hо цель
IT> не отсепарировать математиков, а дать _простое_ объяснение, "на
IT> пальцах". Чтобы было понятно и человеку, который является
IT> специалистом (!) в другой области. Пока что попытка обсудить
IT> методологию приводила в основном к флейму... Определения есть, не
IT> в этом дело. Требуется корректное "вхождение в проблему", чтобы
IT> стало понятно не только, как оно делается, но и зачем.

Жопаскрипт:

function makeAddition(n){
function addN(m){
return n+m;
}
return addN;
}

Берём максимально тупую реализацию, ничего не знающую про замыкания.
Вызываем:

var f = makeAddition(2);
var z = f(3);

Получаем фигню: функция f становится у нас равна addN, но ей для
функционирования требуется переменная n, которой уже нет, потому что
makeAddition уже закончилась.

В языке C мы получим либо мусор, либо вообще какой-нибудь GPF.

В языке с динамическим связыванием мы можем получить не совсем то,
чего ждали, если есть глобальная переменная n:

var f = makeAddition(2);
var n = 10;
var z = f(3);

z (если связывание динамическое) станет равно 13.

В языке с замыканиями функция f будет "помнить" не только то, что она
равна addN, но и то, что переменная n есть 2, и в результате z станет
равно 5. Вот эта фиговина - функция, которая "помнит" локальные
переменные, видимые при её создании, и есть замыкание. При этом может
быть и другая функция, которая "помнит" другие локальные переменные:

var f = makeAddition(2);
var g = makeAddition(3);
var x = f(3);
var z = g(3);

Хотя и f и g - это функция addN, тем не менее x будет равно 5, а z -
6. Потому что f "помнит" n=2, а g "помнит" n=3.

На самом деле, всё может быть ещё интереснее, если использовать
переменные, которые можно изменять. В этом случае нужно иметь в виду,
что замыкание "помнит" не значение переменной, а ссылку на неё:

function makeCounter(){
var val = 0;
function inc(){
val++;
}
function value(){
return val;
}
return {inc: inc; value: value};
}

var counter1 = makeCounter();
var counter2 = makeCounter();
var inc1 = counter1.inc;
var value1 = counter1.value;
var inc2 = counter2.inc;
var value2 = counter2.value;

inc1();
inc1();
inc2();
inc1();
inc2();
var x = value1();
var z = value2();

Теперь x=3 (потому что переменная val из ПЕРВОГО вызова makeCounter
была увеличена трижды), а z=2.
--
Miguel migue...@yandex.ru
LJ migmit http://miguel-0.narod.ru

Dmitry Grebeniuk

unread,
Jul 25, 2007, 3:57:50 AM7/25/07
to
hi, Ilia

IT> Действительно проблема. Я понимаю, что математическая культура,
IT> техника в руках дикаря, голова должна быть и так далее :) Hо цель не
IT> отсепарировать математиков, а дать _простое_ объяснение, "на пальцах".
IT> Чтобы было понятно и человеку, который является специалистом (!) в
IT> другой области. Пока что попытка обсудить методологию приводила в
IT> основном к флейму... Определения есть, не в этом дело. Требуется
IT> корректное "вхождение в проблему", чтобы стало понятно не только, как
IT> оно делается, но и зачем.

Самое простое объяснение -- аналогия с математическим определением
"f(x) := x + y, где y=10".
Вот это "где y=10" является "окружением", связанным с функцией f, а сама f
является closure.
Зачем это делается -- чтобы была возможность вызывать функцию, связанную с
какими-либо значениями, удобным образом. В случае математики довольно просто
переписать f так, чтобы избавиться от окружения: f(x) := x + 10 (хотя в случае
больших функций переписывание тоже зачастую неудобно). В случае современных
процессоров переписывать машинный код (в том числе создавать новый кусок кода
для каждого случая разных y), одновременно сохраняя хорошую производительность,
безопасность и кроссплатформенность, весьма геморройно (хотя и такое делают при
желании).
Получается, что гораздо проще таскать рядом и указатель на машинный код, и
окружение, требуемое для выполнения кода. Таким образом код не меняется, а
меняется окружение.
В случае f(x) имеем 1) указатель на функцию, складывающую первый аргумент (x)
со значением, хранящимся в окружении (y) и 2) само окружение, состоящее из
значения y.

А зачем человеку нужно знать, что такое closure и как оно работает?

bye

Ilia Tarasov

unread,
Jul 25, 2007, 5:58:10 AM7/25/07
to
Wed Jul 25 2007 13:57, Dmitry Grebeniuk wrote to Ilia Tarasov:

DG> Самое простое объяснение -- аналогия с математическим определением
DG> "f(x) := x + y, где y=10".
DG> Вот это "где y=10" является "окружением", связанным с функцией f, а
DG> сама f является closure.

Действительно, без лишних определений. Спасибо, выглядит вполне доходчиво.

DG> А зачем человеку нужно знать, что такое closure и как оно работает?

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

bye

0 new messages