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

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

10 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