Здравствуйте, Ikemefula, Вы писали:
I>>>Если человек 20 лет пользовался ящиками/коробками/сумками, и 3-4 года функциями, то вроде как очевидно, какая модель будет более простой для него.
M>>Четай до полного понимания Execution in the kingdom of nouns. «Коробки-ящики» даже близко не описываются ООП/императивщиной.
I>Именно этим и описываются. Ящики-коробки это поведение в чистом виде. ООП и императивщина оно именно про поведение. Функциональщина — про результат.
Отвечаю на все три (начиная с очевидно). Нет, не очевидно. Стоит отличать два потока данных о мире. Первый — наше восприятие мира, модель его поведения пока мы в него не вмешиваемся (feedback). Вторая — модель мира, когда человек пытается его изменить (т.е. выполнить некоторое действие, feedforward). Интересно, что на направлении "действие" ситуация смотрится становится немного (на самом деле — много) другой. И ведь при этом основная задача программиста — "отдавать команды", т.е. производить feedforward. От удобства feedforward и его связи с feedback зависит удобство языка программирования и скорость понимания. В дальнейшем на feedback я не особо фокусируюсь, там может быть что угодно и на общий результат дискуссии оно не влияет.
Для дальнейшего чтения очень рекомендуется прочитать вторую главу из "The Design of Everyday Things" (revised edition). Там очень много полезных картинок и я буду использовать терминологию оттуда. Например, я буду часто ссылаться на картинку об уровнях обработки информации человеком (в интернете нашел только
здесь, 38-й слайд. Очень рекомендую книгу где-нибудь взять и почитать).
Вводную информацию вроде бы дал. Теперь можно начать моделировать мир. Можно взять какой-нибудь простой классический пример вроде "закрыть дверь". Очень показательный пример на самом деле. В реальной жизни задача "закрыть дверь" имеет два очевидных решения.
Первый вариант: "Вася.закрой(дверь)". Я прошу Васю закрыть дверь за меня. Не смотря на "императивное" указание это на самом деле описание результата "дверь закрыта". Т.е. я хочу чтобы "Вася сделал так, чтобы дверь была закрыта". Я не буду сильно возражать если дверь закроет Петя. Я не прошу выполнять действие (не Вася.закрывай(дверь)). Меня устроит и если Вася делегирует эту обязанность кому-нибудь другому. Меня интересует "результат" (функциональщина в определении выше). У меня нет цели изменить "внутреннее состояние Васи". Я предполагаю, что Вася после закрытия двери не изменится. В общем, с моей точки зрения Вася — это классический иммутабельный объект с поведением. А изменяемый объект (дверь) с моей точки зрения самостоятельного поведения не имеет. "Набор замыканий" из ФП как раз примерно эквивалентен данному объекту.
Второй вариант: "закрою(дверь)". Желание "закрыть" возникает на рефлексивном (reflective) уровне (см. картинку). Детальный план (встать, дойти, протянуть руку, толкнуть дверь) выполняется на поведенческом (behavioral) уровне. Что здесь интересно? А интересно то, что behavioral уровень — это "подсознательный" уровень. Не полностью, он может взаимодействовать с сознанием при необходимости, но в целом достаточно автономен, может разрабатывать детальные действия и контроллировать висцеральный (visceral, мышечные действия) уровень. Подчеркиваю, стимул "закрыть" (описание результата) вырабатывается на сознательном уровне. А вот "план действий" (последовательность операций) вырабатывается по большей части на подсознательном уровне! Это очень важно. Потому что во многих повседневных ситуациях сознание задействуется для решения задачи "что", определения результата. И именно на это сознанине тренировано (плюс иногда оно решает некоторые вычислительные задачи, когда подсознание само не может справиться, но это другая история).
В той же design of everyday things есть хорошее упражнение по прочувствованию разницы между reflective и behavioral.
1. Согните указательный палец.
2. Разогните указательный палец.
3. Сожмите руку в кулак.
4. Разожмите кулак.
5. Возьмите кружку в руку.
6. Налейте воду в кружку.
7. Поставьте кружку на (другой) стол.
А теперь опишите, как именно вы выполняли каждый шаг. О чем думали. Какие "команды" отдавали? На уровне сознания все это обычно редуцируется до "захотел согнуть палец" и "палец сам согнулся". Нижележащий уровень (behavioral) нам не доступен. Мы представляем результат и подсознание выполняет автоматически все операции. Включая обработку обратной связи (тяжесть кружки, колебания воды и т.п.). Эти автоматические операции могут быть достаточно сложными. Например, я на работу/с работы хожу почти автоматически (я не отвлекаюсь на контроль дороги). Подсознание вызывает несколько прерываний (для обработки перехода дорог), все остальное делает само. В принципе, оно на автомате умеет и дороги переходить (нажимает кнопку светофора, ожидает разрешающего сигнала, предпочитает моторный сигнал (вибрацию кнопки вызова) всем остальным индикациям (световой/звуковой)) но обычно я делаю это в ручном режиме, так как это чуть быстрее.
Теперь перейдем к обучению программирования. Выше я пытался показать, что для сознательного мыслительного процесса "целеуказание" является основным процессом в повседневной жизни. Иногда люди создают план, который является набором "достигнутых состояний" а не "каких-то процессов и действий" (действиями на самом деле кодируются промежуточные результаты). Работа программиста — "заставлять машину выполнять действия". Это feedforward и на этом пути мозг как всегда пытается "указывать цель". А вы его заставляете императивщину расписывать! Он ведь не приспособлен к такому. "Как я обычно это делаю? Да не знаю я как, просто делаю и все!". Вы заставляете детализировать весь процесс.
А после детализации наступает второй огромный облом. На поведенческом (behavioral) уровне происходит обработка "обратной связи" от действий и этот поток информации абсолютно необходим для достижения поставленной цели (мозг сравнивает планируемый результат с фактическим). Но у программиста результат детализации выполняет не программист! Его выполняет компьютер. И никакого незамедлительного ответа организму нет. Не понятно, правильно ли все сделано или нет. Нужно запустить программу и сознательно (reflective!) сравнить предполагаемый и полученный результат. Для человеческой "императивной" системы это выглядит как очень сильный облом. Она вроде бы и разработала план, но не получила никакой обратной связи. Появляется подозрение "что-то здесь не так".
В общем не удивительно, что у людей возникает проблема с императивщиной. Потому что мозг (сознательная его часть) не приспособлен изначально к такой модели и задействование "нужных уровней" сознания приводит к неприятным ощущениям (остуствие обратной связи). А вот "функциональщина — про результат" (это не я сказал). Это то, на что сознание натренировано за те 20 лет жизни. Люди ее легко осваивают, получают удовольствие (вместо разочарования) от процесса и одновременно учатся строить необходимые уровни абстракции. А потом уже легко переходят и на императивную модель (в тех местах, где она нужна). Особенно хорошо должно быть начинать с агрессивной "грязной" функциональщины (lisp-, ml- семейства языков). Наличие некоторых побочных эффектов (не на actor!) вполне вписывается в повседневную активность мозга. А вот императивная модель как раз является "абстрактной математикой". С точки зрения той же тренировки мозга "императивное программирование" ровно настолько же неестественно, насколько не естественны абсолютно чистые математические модели. Нет у императивщины "реального аналога", он есто только у "грязной функциональщины".
Ну и касательно уровня абстракций. А кто сказал, что идти нужно снизу вверх? Почему программирование начинается с языков а не с квантовой механики? Программирование же просто несколькими уровнями выше в этой цепочке. И почему в той же школе (и еще раньше, в детстве) начинают с самых верхних (а не нижних!) уровней? Ну там "огонь — бо-бо" а не термодинамика+химия+биология (а там и электрические сигналы, и химия, и нейросети). Может быть, стоит начинать с удобного (и достаточно практичного) уровня? Ну пусть он будет местами неточным. Но зато результат будет раньше и не будет издевательства над мозгом невинных студентов.
P.S. Не нашел, куда вставить. Пусть будет здесь. Уровни "действия" у функциональщины более сбалансированы. "Цель" формулируется сознанием, действие (набор команды) выполняется подсознательно (там нет "последовательности действий, в норме это скорее механическая трансляция разных map/fold/filter/etc...)), проверка высокоуровневого ожидания (результат выполнния)- сознанием, проверка правильности моторики (набор map а не fold) — подсознанием. Все на своем месте. У императивщины детализация (которой в таком виде нет у функциональщины) идет на границе сознания/подсознания а весь результат обрабатывается сознанием.