Дык там всё объяснено, если я сам понял, конечно Это функция, которая использует внешнюю переменную - именно внешнюю, а не передаваемую через параметры. Только это вроде как плохой стиль - понятность и читаемость кода ухудшается. Или я отстал от жизни ?
Пример практически тот же, что и в вики : int x = 10;
int func1(int y) // тут есть замыкание { return x+y; }
int func2(int x, int y) // а тут нет { return x+y; }
ч.е. то не понимаю. вот в приведенном примере с замыканием - x у нас выступает как бы как глобальная переменная, но при этом является локальной? т.е. основная фишка в том, что мы её в функцию не передаем, но по контексту компилятор подставляет правильную переменную?
(я вики раза два прочитал. примеры кодов разобрал, но все равно на голове не уложилось, что это и нахрена надо.)
Про компиляторы лучше не надо, ИМХО - понять не поможет, а действуют они по разному
не обязательно глобальная - т.е. не переменная самого верхнего уровня, а просто внешняя - т.е. переменная, которая определена на уровень или несколько уровней выше, и , как следствие, видна в пространстве имен вложенной функции без объявления...
глобальная - это всё таки когда выше уровня нет
а функция может быть вложена одна в другую - это не существенно, возможно, в данном случае, но разница есть...
основной смысл в том, что используется переменная, явно не определенная и не переданная через параметры - вроде так.
только так делать не стоит - не вижу смысла - экономия писанины мизерная, а вернешься к коду через неделю, или не дай бог, через год, и нихрена не поймёшь
Вообще лучше спросить на каком-то форуме программистов (например, в сообществе www.diary.ru/~programming/ ) - я не программил уже много лет, вдруг ошибаюсь
>> Вообще лучше спросить на каком-то форуме программистов да судя по всему, мой вопрос дюже нубовский. есть подозрение, что регистрироваться, чтобы задать его - лучший способ нарваться на молчание(в лучшем случае) или смехуёчки да пиздахаханьки.
мне кажется у тебя предвзятое отношение к программерам )) Тут вон спрашивают в соседнем сообществе, как устроена девственная плева - и вежливо получают ответы и пожелания удачи Люди становятся добрее, чтоли
с другой стороны - писал тыщу лет без замыканий, ну так и хер с ними.
а вот как устроена девственная плева я, кстати, так и не знаю. сообщество анатомов/антропологов было? ,) или просто вопрос из серии "чо с ней делать?" ? ,)))
Да нет, дело не в локальных и глобальных переменных, а в свободных и связанных.
Замыкание растёт из языков вроде лиспа, и уж там используется в хвост и гриву. Приведу примеры на диалекте лиспа, который так и называется, Clojure («зомыканее»).
(defn kuku [x y] (+ x y))
Эта строчка определяет функцию kuku, которая берёт два аргумента x и y и возвращает их сумму (+ x y). Здесь никаких замыканий нет.
(defn kuku1 [x] #(+ x %))
Эта строчка определяет функцию kuku1, которая берёт один аргумент x и возвращает безымянную функцию #(+ x %). Вот эта безымянная функция и есть замыкание. Она берёт один аргумент y (или называй его как хочешь, здесь название переменной можно не указывать) и возвращает (+ x y).
Это как сопряжённые пространства в математике. Например, бра-кет в квантовой механике: можно рассматривать <ψ|φ> как функцию от двух аргументов ψ и φ, а можно как функцию <ψ| от одного аргумента |φ>.
Ну и вообще функцию от эн аргументов всегда можно переписать как функцию одного аргумента, возвращающую функцию от эн минус одного аргумента.
(defn make-counter [] (let [x (atom -1)] #(swap! x inc)))
Вот мы определили функцию make-counter, которая никаких аргументов не берёт, создаёт переменную x, равную минус единице, и возвращает безымянную функцию #(swap! x inc), которая при каждом вызове увеличивает x на один и возвращает. Вот мы даём ей имя:
(def c1 (make-counter))
Вызываем (c1). Она возвращает 0. Вызываем ещё раз. Возвращает 1. Вызываем ещё раз. Возвращает 2. И так далее.
(def c2 (make-counter))
Вызываем (c2), возвращает 0. Ещё раз. 1. Вызываем (+ (c1) (c2)). Возвращает 5. Вызываем ещё раз. Возвращает 7. Ещё раз. 9. И так далее.
А вот так такой же счётчик выглядит на common lisp, тоже через замыкание (из какой-то пдфки на просторах интернета):
(defun make-counter () (let ((x -1)) (lambda () (setq x (+ x 1)))))
Блин, я чото как начал писать, как начал, и уже пару страниц налабал, а все объяснение идет и идет. Кажется, я не то пишу. Допустим, в разделе "ссылки" в википедийной статье есть чудная статья - habrahabr.ru/blogs/webdev/38642/ Там есть примеры.
Но вопрос-то в другом стоит, если я правильно понимаю. Примеров дохера, вопрос - как ООП-щику понять, зачем нужно замыкание? Ответ - никак. ООП-щику оно не надо. Чтобы замыкание заиграло смыслом, надо чтобы язык этому способствовал. В русском нет артиклей, но есть окончания. В английском - наоборот. Как объяснить русскому, зачем использовать артикли? Пока он говорит по-русски - незачем.
1. Область видимости. У ООПа для этого есть классы и область видимости. В javasсript нет классов. И чтобы спрятать переменную от другого скрипта, я могу разве что в замыкание ее спрятать.
2. Связи между объектами (контекст исполнения). В ООПе все просто - есть кнопка, по кнопке щелкнули, в обработчике есть обращение к this. Что такое this? Правильно, кнопка, объект, у нас же объектно-ориентированный язык. В функциональном языке этим this скорее всего окажется... сама функция-обработчик. Чо делать? Ага, перед определением обработчика написать var context = this;, где this - это кнопка. И в обработчике обращаться к context, сохраненному замыканием.
Вот эти примеры все в википедии - нафига человеку создавать "специализированную функцию из более общей"?
Там пример на Lua замечательный. Функция "плюсователь_на_два". Зачем такое делать? Ну был бы у меня ООП, я б двойку передал в конструктор и сохранил в приватной переменной. И при вызове метода к параметру прибавлял бы эту приватную переменную. А в жабаскрипте у меня нету классов. Нет приватных переменных. Есть замыкание. Вот и извращаюсь как могу, да.
>>хорошо бы пример из жизни. когда замыкание - лучший способ решить задачу.
Замыкание - это, чаще всего, не "лучший способ решить задачу". Чаще - единственно возможный из-за синтаксиса языка. Иногда - более краткий с точки зрения синтаксиса. Но чтобы "лучший" - хм...
Tzota вот. спасибо тебе даня, ответил таки на вопрос "нахера козе баян". я ж пытался в голове сложить ООП и замыкания - и таки мозгу нехорошо было. а вот теперь идеология кристальная ясна.
тебе надо преподавательствовать или учебники писать. =)
Сложить ООП и замыкания можно. Но особой потребности в этом, чаще всего, нет. Да, есть случаи, когда это экономит пол страницы кода. Но чтобы без этого "не жить" - нееее.
-
-
16.11.2010 в 20:55Это функция, которая использует внешнюю переменную - именно внешнюю, а не передаваемую через параметры.
Только это вроде как плохой стиль - понятность и читаемость кода ухудшается.
Или я отстал от жизни ?
Пример практически тот же, что и в вики :
int x = 10;
int func1(int y) // тут есть замыкание
{
return x+y;
}
int func2(int x, int y) // а тут нет
{
return x+y;
}
-
-
16.11.2010 в 21:04(я вики раза два прочитал. примеры кодов разобрал, но все равно на голове не уложилось, что это и нахрена надо.)
-
-
16.11.2010 в 21:11не обязательно глобальная - т.е. не переменная самого верхнего уровня, а просто внешняя - т.е. переменная, которая определена на уровень или несколько уровней выше, и , как следствие, видна в пространстве имен вложенной функции без объявления...
глобальная - это всё таки когда выше уровня нет
а функция может быть вложена одна в другую - это не существенно, возможно, в данном случае, но разница есть...
основной смысл в том, что используется переменная, явно не определенная и не переданная через параметры - вроде так.
только так делать не стоит - не вижу смысла - экономия писанины мизерная, а вернешься к коду через неделю, или не дай бог, через год, и нихрена не поймёшь
-
-
16.11.2010 в 21:12-
-
16.11.2010 в 21:17по ходу понять и прочувствовать поможет только написание примеров.
ведь для чего-то это замыкание придумали? не для того ж, чтоб экономить при вызове один аргумент, имея после этого кучу гемороя с поддержкой кода.
-
-
16.11.2010 в 21:18-
-
16.11.2010 в 21:19-
-
16.11.2010 в 21:20-
-
16.11.2010 в 21:22да судя по всему, мой вопрос дюже нубовский. есть подозрение, что регистрироваться, чтобы задать его - лучший способ нарваться на молчание(в лучшем случае) или смехуёчки да пиздахаханьки.
-
-
16.11.2010 в 21:25Тут вон спрашивают в соседнем сообществе, как устроена девственная плева - и вежливо получают ответы и пожелания удачи
Люди становятся добрее, чтоли
-
-
16.11.2010 в 21:30а вот как устроена девственная плева я, кстати, так и не знаю. сообщество анатомов/антропологов было? ,) или просто вопрос из серии "чо с ней делать?" ? ,)))
-
-
16.11.2010 в 21:32Ну тока это.. не обижайте маленьких
-
-
16.11.2010 в 21:34>>не обижайте маленьких
там народ и так оторвался =)
но в целом оборжали по-доброму так. не зло. даже удивлен.
-
-
17.11.2010 в 18:32Замыкание растёт из языков вроде лиспа, и уж там используется в хвост и гриву. Приведу примеры на диалекте лиспа, который так и называется, Clojure («зомыканее»).
(defn kuku [x y] (+ x y))
Эта строчка определяет функцию kuku, которая берёт два аргумента x и y и возвращает их сумму (+ x y). Здесь никаких замыканий нет.
(defn kuku1 [x] #(+ x %))
Эта строчка определяет функцию kuku1, которая берёт один аргумент x и возвращает безымянную функцию #(+ x %). Вот эта безымянная функция и есть замыкание. Она берёт один аргумент y (или называй его как хочешь, здесь название переменной можно не указывать) и возвращает (+ x y).
Это как сопряжённые пространства в математике. Например, бра-кет в квантовой механике: можно рассматривать <ψ|φ> как функцию от двух аргументов ψ и φ, а можно как функцию <ψ| от одного аргумента |φ>.
Ну и вообще функцию от эн аргументов всегда можно переписать как функцию одного аргумента, возвращающую функцию от эн минус одного аргумента.
-
-
17.11.2010 в 18:56-
-
17.11.2010 в 20:03-
-
17.11.2010 в 20:04(defn make-counter [] (let [x (atom -1)] #(swap! x inc)))
Вот мы определили функцию make-counter, которая никаких аргументов не берёт, создаёт переменную x, равную минус единице, и возвращает безымянную функцию #(swap! x inc), которая при каждом вызове увеличивает x на один и возвращает. Вот мы даём ей имя:
(def c1 (make-counter))
Вызываем (c1). Она возвращает 0. Вызываем ещё раз. Возвращает 1. Вызываем ещё раз. Возвращает 2. И так далее.
(def c2 (make-counter))
Вызываем (c2), возвращает 0. Ещё раз. 1. Вызываем (+ (c1) (c2)). Возвращает 5. Вызываем ещё раз. Возвращает 7. Ещё раз. 9. И так далее.
А вот так такой же счётчик выглядит на common lisp, тоже через замыкание (из какой-то пдфки на просторах интернета):
(defun make-counter ()
(let ((x -1))
(lambda () (setq x (+ x 1)))))
-
-
17.11.2010 в 20:50-
-
18.11.2010 в 10:50BlindPew Это, уважаемый, теперь называется не "плохой стиль", а "модное функциональное программирование", ага )))
-
-
18.11.2010 в 11:07-
-
18.11.2010 в 14:35Допустим, в разделе "ссылки" в википедийной статье есть чудная статья - habrahabr.ru/blogs/webdev/38642/
Там есть примеры.
Но вопрос-то в другом стоит, если я правильно понимаю. Примеров дохера, вопрос - как ООП-щику понять, зачем нужно замыкание? Ответ - никак. ООП-щику оно не надо. Чтобы замыкание заиграло смыслом, надо чтобы язык этому способствовал. В русском нет артиклей, но есть окончания. В английском - наоборот. Как объяснить русскому, зачем использовать артикли? Пока он говорит по-русски - незачем.
1. Область видимости. У ООПа для этого есть классы и область видимости. В javasсript нет классов. И чтобы спрятать переменную от другого скрипта, я могу разве что в замыкание ее спрятать.
2. Связи между объектами (контекст исполнения). В ООПе все просто - есть кнопка, по кнопке щелкнули, в обработчике есть обращение к this. Что такое this? Правильно, кнопка, объект, у нас же объектно-ориентированный язык. В функциональном языке этим this скорее всего окажется... сама функция-обработчик. Чо делать? Ага, перед определением обработчика написать var context = this;, где this - это кнопка. И в обработчике обращаться к context, сохраненному замыканием.
Вот эти примеры все в википедии - нафига человеку создавать "специализированную функцию из более общей"?
Там пример на Lua замечательный. Функция "плюсователь_на_два".
Зачем такое делать?
Ну был бы у меня ООП, я б двойку передал в конструктор и сохранил в приватной переменной. И при вызове метода к параметру прибавлял бы эту приватную переменную.
А в жабаскрипте у меня нету классов. Нет приватных переменных. Есть замыкание. Вот и извращаюсь как могу, да.
>>хорошо бы пример из жизни. когда замыкание - лучший способ решить задачу.
Замыкание - это, чаще всего, не "лучший способ решить задачу". Чаще - единственно возможный из-за синтаксиса языка. Иногда - более краткий с точки зрения синтаксиса. Но чтобы "лучший" - хм...
-
-
18.11.2010 в 15:37-
-
18.11.2010 в 17:44а вот теперь идеология кристальная ясна.
тебе надо преподавательствовать или учебники писать. =)
-
-
18.11.2010 в 18:55Сложить ООП и замыкания можно. Но особой потребности в этом, чаще всего, нет. Да, есть случаи, когда это экономит пол страницы кода. Но чтобы без этого "не жить" - нееее.