Skip to content
efelikanfuzin edited this page Jul 7, 2016 · 4 revisions

warden13 [08:54]

function makeAdder(x) {    
   function add(y){
     return x + y;
   }    
   return add;
}
var plusOne = makeAdder(1);console.log(plusOne(1));

Мне здесь непонятно, почему аргумент в plusOne передается внутрь как y для add

rabinzon [08:56] у тебя makeAdder принимает аргумент x и возвращает другую функцию add - plusOne которая принимает y (edited)

warden13 [08:59] Спасибо, вроде догоняю

point212 [08:59] жесть какая.

[09:00] как так то? там же вообще по идее y не откуда взяться.

azmesmparser [09:00] plusOne просто новое имя для add

warden13 [09:00] Вот я тоже над этим думал долго))

point212 [09:00] А если я просто вызову console.log(plusOne(1));

fatwebdev [09:00] в plusOne лежит const add = y => 1 + y;

rabinzon [09:02] add = (x,y) => { return x + y } что вернет add?

point212 [09:03] саму функцию наверное

fatwebdev [09:03] Оо

rabinzon [09:03] add(5,5)

warden13 [09:03] сумму аргументов

rabinzon [09:03] ?

warden13 [09:03] 10 вернет

rabinzon [09:04] const sum = add(5,5) где sum = 10

point212 [09:04] Неправильно вопрос понял.

rabinzon [09:04] точно так же вместо чисел можно вернуть функцию из функции

point212 [09:04] Ну это я понимаю 🙂 Допустим вернули.

kirill.mokevnin [09:05] вопрос на засыпку, а как вызывать эту функцию const sum = x => y => x + y чтобы она вычислила x + y ?

point212 [09:05] Ей получается опять подставятся аргументы, которые были переданы изначальной функции?

kirill.mokevnin [09:05] щас проверим ваше понимание

point212 [09:05] я и так не понимал 🙂 теперь вообще перестану

**warden13 [09:05] sum(1,2) ???

kirill.mokevnin [09:05] там же видно что аргумент у sum один

pustato [09:06] sum(1)(2)?

kirill.mokevnin [09:06] бинго

warden13 [09:07] C каждым сообщением все больше понимания)

point212 [09:07] С каждым сообщением всё меньше понимания (

*rabinzon [09:08] function sum(x) { return function inner(y) {x +y} }

мы из sum вернем другую функцию inner которая готова принять аргумент

warden13 [09:08] Еще вопрос на счет объявления функций. В чем преимущество const someFunc = x => {} от

[09:09] var someFunc = funtion(x) {}

kirill.mokevnin [09:09]

чтобы не вдаваться в детали, которые вас сейчас запутают, мы в курсах даем именно такое определение потому что оно очень хорошо показывает (и намекает) на то что функции это тоже данные

point212 [09:09] А откуда она возьмёт аргумент? Опять из тех аргументов, которые были переданы изначальной функции? и вызовется вместо неё? Или это произойдёт лишь при втором вызове?

kirill.mokevnin [09:09] и между данными и функциями нет разницы по большому счету (в языках где есть разница это особенность реализации, в математике нет разницы)

[09:10] этого достаточно на текущем уровне, остальное уже связано с особенностями работы вокруг this

[09:10] не забивайте голову

[09:10] лучше разберите тот пример до конца

warden13 [09:10] в closure?

kirill.mokevnin [09:10] там и замыкания и функции как данные

[09:11] `const sum = x => y => x + y``

[09:11] вот этот пример который в себе содержит все о чем вы говорите

[09:11] его понимание даст вам полное понимание происходящего

point212 [09:11] @rabinzon: пойдёмте в директ. чтобы остальным не мешать 🙂 может у вас получится мне обяснить 🙂 потому что мне кажется, я начинаю догонять

rabinzon [09:11] function sum(x) { return function inner(y) {x +y} } var fn = sum(4); @point212: чему равно fn ?

kirill.mokevnin [09:11] ребят это тут и надо обсуждать

kirill.mokevnin [09:11] хекслет для этого создавался

[09:12] и general самый тот канал где нужно разбирать непонимание фундаментальных вещей

point212 [09:12] ну просто тут у всех вопросы... параллельно несколько обсуждений вести неудобно же

kirill.mokevnin [09:12] все ваши вопросы сводятся к той функции которую я выше описал

[09:12] давйате все вместе разберем

[09:12] сэкономим всем время

point212 [09:12] Ну я честно говоря не понял даже синтаксиса. Что за =>

kirill.mokevnin [09:12] мне гораздо проще/удобнее сразу всем рассказать, чем потом каждому в отдельных чатах

point212 [09:12] типа объявление функции в js?

kirill.mokevnin [09:12] да

rabinzon [09:13] @point212: я написал через function)

kirill.mokevnin [09:13] простейшая функция в js которая называется identity: const identity = x => x

[09:13] идентичность, возвращает переданный аргумент

arbatskiy [09:13] получется эта функция y => x + y, будет теперь таскать за собой x, как туз в рукаве, и в лбом месте ее использовать, где эту функцию решат вызвать

kirill.mokevnin [09:13] теперь дальше const sum = x => y => x + y

[09:13] вы можете тут расставить скобки?

[09:14] скиньте сюда этот же пример, но так чтобы тело функции было обернуто в скобки () [09:14] не важно может ли этого синтаксис js или нет, мы щас для концептуального понимания

warden13 [09:14] const sum = x => ( y => x + y ) ?

kirill.mokevnin [09:14] воооот

[09:15] сколько принимает аргументов sum и что возвращает?

warden13 [09:15] 1 аргумент и возвращает функцию

kirill.mokevnin [09:15] @warden13: я вижу что вы понимаете, давайте другим дадим)

kirill.mokevnin [09:16] @point212: напиши плс определение функции, которую мы получим вызвав функцию выше вот так sum(5)

[09:16] и назови ее const plusFive

[09:16] то есть вот эту запись const plusFive = sum(5) надо развернуть в определение функции

arbatskiy [09:16] а как правильно сформулировать тут, что x замкнуто для функции? или функция замкнута для x?

kirill.mokevnin [09:16] эквивалентное

warden13 [09:17] получается в plusFive будет хранится функция y => 5 + y ?

[09:18] @warden13: да, но надо чтобы это другие осознали

warden13 [09:19] И толк от многих видеообъяснений, когда есть слак)

kirill.mokevnin [09:21] ок, пока вы изучаете пример выше

[09:21] даю более сложный

[09:21]

const sum = x => {
  const inner = y => {
    return x + y;
  };

  x = 10;
  return inner;
}
console.log(sum(1)(5))

point212 [09:21] const sum = x => (y => (x + y)) вот так вот, нет?

kirill.mokevnin [09:21] что будет введено на экран?

[09:21] @point212: да, абсолютно верно

arbatskiy [09:22] интересный пример! не буду говорить предположения, подожду других 🙂

warden13 [09:23] 6

arbatskiy [09:23] по идее Inner должна тащить за собой свое окружение, в том числе x = 10, я так думаю

point212 [09:24] Т.е. когда для вот этой функции const sum = x => y => x + y вызвается sum(1)(5) - первый раз вызывается внешняя функция, и ей передается 1, а потом уже ка результат ее вызывается внутренняя, и ей передается 5. Типа (sum(1))(5). Я правильно понял?

kirill.mokevnin [09:24] правильно, но тут тонкий семантический момент, после вызова первой функции, вам наружу возвращается внутренняя

[09:24] поэтому она вызывается не внутри первой, а снаружи, после вызова первой

[09:24] вот этот момент понятен?

[09:25] по сути вы внутри определяете новую функцию const f = ... и ниже делаете return f;

[09:25] поэтому можно было бы написать const plusOne = sum(1)

[09:25] вот эта функция вернулась

point212 [09:25] Да. Теперь понятен.

kirill.mokevnin [09:25] и дальше где угодно plusOne(10)

[09:25] на выходе 11

[09:26] как видите функции это данные

[09:26] их можно и возвращать из функций и передавать в другие функции

point212 [09:26] А если опять plusOne(10)? Оно опять по кругу пойдёт? Или это уже будет только лишь вернувшаяся функция работать?

kirill.mokevnin [09:26] а вот выше вопрос был, напишите определение этой функции plusOne сюда

[09:26] тогда вы сразу все поймете

point212 [09:27] Да. Это я и раньше понимал. 🙂 Но применял очень ограниченно.

kirill.mokevnin [09:27] ну так напишите)

point212 [09:27] Сейчас прочитаю и осмыслю и напишу

kirill.mokevnin [09:27] кстати сущности языка обладающие такими свойствами называются объектами первого рода (класса), слово объект тут используется в общем смысле "какая-то хрень"

point212 [09:27] Это же мы уже про более сложный пример, который

const sum = x => {
 const inner = y => {
   return x + y;
 };  x = 10;
 return inner;
}
console.log(sum(1)(5))

kirill.mokevnin [09:27] не

[09:27] это про plusOne

[09:28] А если опять plusOne(10)? Оно опять по кругу пойдёт? Или это уже будет только лишь вернувшаяся функция работать? вот этот вопрос говорит что вы не до конца понимаете что теперь из себя представляет функция plusOne

point212 [09:29] Да просто мы тут уже написали кучу разных кусков кода. И который из них plusOne я запутался.

kirill.mokevnin [09:29] const plusOne = sum(1)

[09:29] const sum = x => y => x + y

[09:29] нужно написать определение функции plusOne эквивалентное тому что написано выше

[09:30] чтобы было понятно, что в ее теле

[09:30] и пойдет ли оно по кругу

point212 [09:30] Маленький вопросик, т.к. я JS не знаю. const это просто объявление переменной или реально константа?

kirill.mokevnin [09:30] константа да

[09:30] вам не нужен новый синтаксис чтобы это написать

[09:30] все есть тут

[09:31] const plusOne = ...

warden13 [09:31] Я писал 6, но потом понял что когда выполняется return inner, функция за параметр х возмет 10, т.к. он встретиться первым при поиске того самого параметра, следовательно sum(1)(5) вернет 15, а не 6. Она просто не дойдет до х=1

kirill.mokevnin [09:31] что будет вместо троеточия

[09:31] @warden13: ответ правильный, но размышления которые к нему привели - нет

[09:32] это называется позднее связывание (то самое которое алан кей называет главной фичей ооп)

warden13 [09:32] Позднее связываение - это тот же hoisting?

kirill.mokevnin [09:33] @point212: сейчас ответственный момент для того чтобы в голове сработало "эврика" и все встало на свои места

[09:33] нет

[09:33] hoisting это особенность реализации движка js

[09:33] очень специфичная штука

[09:33] хотя вру, hoisting в спецификации описан

[09:33] изначально так просто движок сделали

[09:33] потом стандартизировали

[09:33] щас убежусь на всякий)

point212 [09:34] у меня в голове сработала защита пока что. Хочется зажмуриться и сделать ресет мозгу

[09:34] Секунду. Сейчас опять от работы отобьюсь чтобы не мешали думать

kirill.mokevnin [09:34] давайте, просто вот это тот барьер который надо сломать

[09:34] иначе все время стенка будет

[09:35] так вот про позднее связывание и пример выше

[09:36] js работает по, так называемой, модели окружениями

[09:36] окружение это область памяти в которой записываются key value пары

[09:36] это очень важно, еще раз повторю окружение это область памяти

[09:36] хм, чот жирный не сработал)

[09:36] когда вы пишите const x = 5;

[09:37] то где то в кишках js создается ассоциативный массив в который это дело записывается

[09:38] но чтобы про эту модель дальше говорить, нужно проговорить другую модель, которая гораздо более простая и разбирается в первых двух главах сикп

[09:38] это подстановочная модель вычислений

[09:40] это крайне простая вещь, главное что в ней происходит это бета редукция

[09:40] то есть когда у вас есть функция const sum x => y => x + y, то она по сути заменяет имена на их значения

[09:41] это возможно только в случае неизменяемости

[09:41] если x = 5, то это не присваивание (в такой модели), это логическое выражение

[09:41] как в математике "допустим x это 5"

[09:41] и оно не может поменяться

[09:42] и это дает вам возможность все последующие вхождения x заменить на 5

[09:42] и ваша программа (на самом деле теорема) остается корректной

[09:42] вы всегда можете представлять вычисление программы как последовательность бета редукций подстановок)

[09:43] до тех пор пока у вас выражение не развернется в плоское арифметическое 5 + 3 * 7 - 9

[09:43] которое уже редуцируется до конкретного числа

[09:43] что не понятно? 😄

[09:43] краткое изложение сикпа за 5 минут

point212 [09:43] Вот как раз последние 3 строчки весьма понятно.

kirill.mokevnin [09:44] @point212: а от вас я жду определение функции)

point212 [09:44] Это как в математике x + ( x + y + ( x - y))

kirill.mokevnin [09:44] это и есть математика 😉

point212 [09:44] никакх проблем с передчей внутрь скобок Х нету.

[09:44] Да. Но будучи записанной согласно синтаксису она теряет наглядность

kirill.mokevnin [09:44] это уже ваши тараканы

point212 [09:44] Я толкьо вернулся к компу ) Сейчас перечитаю и напишу

kirill.mokevnin [09:44] функциональные языки так и устроены (семантически)

[09:44] по факту конечно все работает гораздо сложнее, но снаружи поведение именно такое

[09:45] поэтому можно его именно так и моделировать

point212 [09:45] да. это я тоже видел. просто в математике эту простую вещь не называют замыканиями 🙂

kirill.mokevnin [09:45] а вот модель с окружениями на порядок сложнее, она необходима из за изменяемости

[09:45] в математике замыкание это совершенно другое да, мы об этом понятии в курсе говорим

[09:45] замкнутые множества вот это все

[09:46] модель с окружениями требует наличия как раз такой области памяти в которой хранится связь между именем и значением

[09:46] из за того что значение может менятся

[09:46] поэтому получается что когда вы делаете

const sum = x => {
 const inner = y => {
   return x + y;
 };

 x = 10;
 return inner;
}

console.log(sum(1)(5))

[09:46] вот эта строчка return x + y;

[09:47] еще кое что забыл, окружения бывают двух видов

[09:47]

  1. глобальное
  2. локальные

kirill.mokevnin [09:47] глобальное одно, локальное каждый раз при заходе в функцию организуется

[09:47] у каждой функции свое локальное

[09:47] и они так выстраиваются в цепочки

[09:48] в итоге js (да любой язык с такой моделью) внутри себя содержит дерево из этих окружений

[09:48] globalEnv -> local1 -> local2

[09:48] это только одна из веток

[09:48] будут еще globalEnv -> local22 -> local23

[09:48] напомню что каждое окружение это табличка key value

[09:48] где key это имя типа const x

[09:48] а значение это собственно значение

[09:49] так вот как происходит отработка этого кода выше

[09:49] return x + y;

[09:49] нам нужно подставить x

[09:49] js смотрит в текущее окружение (текущий локальный скоп)

[09:49] и не видит там x

[09:49] говорит текущему скоупу, ну ка дай мне своего родителя

[09:49] и смотрит у него

[09:49] там уже находит x

[09:49] и говорит скоупу, ну ка дай текущее значение

[09:49] и какое у него текущее значение?

warden13 [09:49] 10

kirill.mokevnin [09:50] вооот

[09:50] так оно и рабтает

[09:50] просто же?)

warden13 [09:50] Получается я не совсем неправильно мыслил, он все таки первым натыкается на х=10 и с ним работает, не доходя до параметра х в аргументах

[09:50] А так да, очень просто

arbatskiy [09:51] о, я какжется догаладся как оно должно быть)

kirill.mokevnin [09:51] этой модели миллион лет

[09:51] появилась в лиспах задолго до рождения нашего

pavel-k [09:51] если бы этот разговор состоялся вчера, то решение логики без логики заняло бы у меня 3 минуты вместо 30 😃

kirill.mokevnin [09:51] которому тридцатка (edited)

warden13 [09:52] Я заметил edit ))))

kirill.mokevnin [09:52] я посчитал не правильно)

[09:52] так ну ским появился в 70

[09:52] так что минимум 46 лет)

[09:52] но я уверен что и до него это было

[09:53] в одной из первых версий лиспа маккартни

[09:53] это шестидесятые

[09:53] @point212: мы ждем определение функции

[09:53] я не отстану! 😄

point212 [09:54] Пишу в блокнотике рядом. Вроде уже даже написал.

[09:54] И откуда у вас только желание с каждым возиться и в голову вбивать. Это ж никаких сил не хватит на всех.

kirill.mokevnin [09:55] представьте что мы уже больше года тут этим занимаемся)

pavel-k [09:56] говорят, что чем больше объясняешь другим, тем лучше понимаешь сам...

kirill.mokevnin [09:57] мы на самом деле создали хекслет чтобы научиться программировать 😄

konstantin6487 [09:58] Вроде это и есть самое основное. Как функции вызывают друг друга. На codewars я 3 уровня набрал и дальше тупик. Не то что проблема в непонимании JS, а в непонимании принципа программирования,

point212 [09:58]

Дано:

  const sum = x => y => x + y

  const plusOne = sum(1)

Ход решения:

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

sum =  x => ( y=>(x + y) )

не понятно. перепишем в привычном виде.

func sum(x){
  func inn(y){
    ret x+y
  }
}

вроде вот так.

Тогда после выполнения

const plusOne = sum(1)

plusOne должно быть

plusOne = func inn(y) { ret 1 + y }

Т.е. пока что ничего не вычислено.

kirill.mokevnin [09:59] все правильно const plusOne = y => 1 + y;

[10:00] вы задавали вопрос: "пойдет ли оно по кругу"

[10:00] ответите теперь сами?

point212 [10:05] Не пойдёт.

[10:05] Если вызвыать ещё одни раз, уже const Two = plusOne(2) = 1+ 2;

kirill.mokevnin [10:06] ну и теперь должно быть довольно очевидно что мы можем делать любую вложенность: const sum = x => y => z => x + y + z

warden13 [10:07] const sum = x => { const innerSum = y => { const secondInnerSum = z => { return x + y + z; } return secondInnerSum; } return innerSum; }const plusOne = sum(1); const plusTen = plusOne(9);

[10:07] Я это написал 5 минут назад))

kirill.mokevnin [10:08] для закрепления такой пример: const compose = x => y => value => x(y(value))

arbatskiy [10:08] кстати про юдасити, вот в этом курсе как раз рассказывают про всякие скоупы довольно подробно и с картинками https://classroom.udacity.com/courses/ud015

kirill.mokevnin [10:08] кто может привести пример использования?

konstantin6487 [10:08] При вызове функции, куда бы её ни передали в коде – она будет искать переменные сначала у себя, а затем во внешних LexicalEnvironment с места своего «рождения». Вы про это?

almazsr [10:08] Суперпозиция функций

matvey.bogomolov [10:10] Ооо, жаль.. такие разборки пропустил) А кто-нибудь читал статьи про лямбда абстракции по ссылке из задания "Числа Чёрча"? Вот это конечно темка, не для слабонервных)

kirill.mokevnin [10:11] console.log(compose(x => x * 5)(x => x - 10)(100));

arbatskiy [10:11] compose(isEven)(plusOne)(2)

kirill.mokevnin [10:11] что выдаст этот вызов?)

[10:12] я понял что нам надо добавить в квизы на сайт

almazsr [10:12] 490?

arbatskiy [10:12] 450?

kirill.mokevnin [10:12] ушел обновлять курсы

warden13 [10:12] 450

kirill.mokevnin [10:12] кто еще как думает?)

[10:12] @point212: ?

point212 [10:13] Не понятная запсь эта... это же не вызов функции. Чтобы во что-то развренулось надо вызвать.

konstantin6487 [10:13] 490

matvey.bogomolov [10:13] 490

vitalyusov [10:13] 450

kirill.mokevnin [10:13] как это не вызов [10:13] name() - это вызов

point212 [10:13] Я про вот это const compose = x => y => value => x(y(value))

kirill.mokevnin [10:14] правильный ответ 450

warden13 [10:14] УРА!)))

roman_gemini [10:14] @arbatskiy: false 🙂

almazsr [10:14] Да, 450. Порядок перепутал

atosdo [10:14] (100 - 10) * 5

kirill.mokevnin [10:14] хехе

konstantin6487 [10:15] Я посчитал не правильно,!

kirill.mokevnin [10:15] вот когда у вас такие штуки в голове будут на раз два раскладываться, можете считать что произошел левел ап

point212 [10:15] @kirill.mokevnin: так я правильно понимаю что выражение const compose = x => y => value => x(y(value)) это пока не вызов функции?

kirill.mokevnin [10:15] да это определение

[10:15] как обычно сначала расставьте скобки вокруг тел функций

[10:15] чтобы было видно

point212 [10:16] И вызвать ее правильно можно только вот так compose(1)(2)(3)

[10:16] т.е. если вызовем лишь compose(1) ничего не посчитается,

kirill.mokevnin [10:16] да, и вопрос был в том что вернется при таком вызове console.log(compose(x => x * 5)(x => x - 10)(100));

[10:16] compose(1)(2)(3) упадет с ошибкой

point212 [10:17] Ну я до этого не дошёл ещё. Я --> :slowpoke:

[10:17] Почему упадёт с ошибкой? Потому что ожидает что первые два вызова будут функцями в обязательном порядке?

vitalyusov [10:18] будет пытаться вызывать 2 и 1 как функции

[10:18] а это не функции

[10:18] так?

warden13 [10:18] Вроде да

warden13 [10:19] x(y(value)) - тут уже х и у вызываются как функции

vitalyusov [10:19] только объявляются

point212 [10:20] console.log(compose(x => x * 5)(x => x - 10)(100)) развернется в 450<-((100-10)*5)<-(100-10)<-(100)

[10:20] Я так понял?

[10:21] @kirill.mokevnin: проверьте пожалуйста ход моих рассуждений.

konstantin6487 [10:22] очевидно что да

matvey.bogomolov [10:22] Вроде да.

count [10:22]

const madness = ({a}) => ((a) =>(([{a}]) => (a *= 7, (a => ({a: a})))(a))(a))(a);
console.log(madness({a: [{a: 6}]}).a);

point212 [10:23] Спасибо, ребята )))

kirill.mokevnin [10:23] самое главное что это знание не конкретного языка

[10:23] это общая концепция пришедшая к нам из лямбда исчисления

[10:24] зная ее, вы на любом языке сможете писать эффективно, где поощрается использование функций высшего порядка

point212 [10:24] Я до этого думал что понимаю как работают компиляторы/интерпретаторы. И вообще компьютер. Как парсится код. Но таких вещей в моей "детской" практики не встречалось. Вот что значит учиться программированию по настоящему. Как науке. А не тому, чему учат у нас в институтах.... И понятно теперь почему всё седые гуру программирования говорят - учите сначала ЛИСП.

konstantin6487 [10:25] Вот кстати развернуто про это из собеседования: определите на каком уровне вы? https://habrahabr.ru/post/226325/

point212 [10:25] Надо перепройти ту лекцию Руби, где про аккумулятор. Может теперь пойму как оно считается

kirill.mokevnin [10:25] лучше пройти курс "основы программирования"

[10:25] там очень хорошо разбирается итеративный процесс на рекурсивных функциях

point212 [10:25] @kirill.mokevnin: вам отдельно спасибо за возню

kirill.mokevnin [10:26] главное чтобы хороших программистов становилось все больше

matvey.bogomolov [10:26] Вроде немного по другому же там. Там все левоассоциативно вычисляется. Если я правильно понял. Т.е. f1 f2 f3 f4 == (((f1 f2) f3) f4) я про лямбда исчисление и к тому, что есть небольшие отличия, усложняющие восприятие. Тут так, там иначе но основа то да, она одна

kirill.mokevnin [10:26] сходимость равенство гильберово пространство! вступайте в ряды фурье! -)

Clone this wiki locally