Почему стоит задуматься о функциональном программировании: плюсы, минусы и применение

Как известно, программисты — люди творческие, но вместе с тем ревностно придерживающиеся определенных идей, к примеру, выбора языка программирования. PHP считается языком «для ленивых», а JavaScript — «труднопрогнозируемой» магией. И среди огромного обилия языков функциональные языки все быстрее обрастают поклонниками и все увереннее прокладывают себе путь в большинство компаний по всему миру. Согласно аналитике RedMonk от июня 2017 и сборной оценке популярности языков на GitHub и Slack Overflow, функциональные языки (Elm, Elixir) медленно, но уверенно набирают рост. Огромный рост популярности JavaScript также ведет к повышенному интересу к ФП. Вдобавок, разработчики с опытом в функциональном программировании впоследствии начинали работать над SPA фреймворками, и, как результат, у нас есть Redux, React, MobX и другие библиотеки, которыми пользуются миллионы людей.

Так что же такое функциональное программирование, откуда такой бум и почему стоит задуматься о его изучении? Давайте разбираться.

Немного азов

Прежде чем уходить в дебри, стоит начать со старта.

Мир JavaScript кипит. Несколько лет назад лишь немногие разработчики имели представление о функциональном программировании, а вот за последние три года практически каждая кодовая база крупных приложений активно использует идеи, взятые из мира функционального программирования. И на то есть объективные причины: функциональное программирование позволяет писать более сжатый и предсказуемый код, его легче тестировать (хотя изучение с нуля дается нелегко).

Основные отличительные признаки разработки ПО при помощи ФП:

  • компоновка чистых функций;
  • избегание разделяемого состояния (shared state), изменяемых данных (mutable data) и побочных эффектов (side-effects);
  • превалирование декларативного, нежели императивного подхода.

Функциональное программирование по своей сути основывается на фундаментальных, определяющих принципах, перечисленных выше. И чтобы начать их постигать, сперва стоит переключиться в «академический» режим и как следует изучить определения терминов, которые будут неотступно преследовать вас в ФП: чистые функции, композиция функций, избегание разделяемого состояния и т. п. Это больше похоже на возврат в школу на урок математики — зато после этого вы совершенно по-другому будете смотреть и на функциональное, и на программирование в целом.

Давайте немного углубимся в термины ФП и минимально поверхностно разберемся, что они значат.

Чистые функции — это детерминированные функции без побочных эффектов. Детерминированная функция означает, что для одного и того же набора входных значений она возвращает одинаковый результат. Для ФП свойства таких функций очень важны: к примеру, чистые функции обладают ссылочной прозрачностью — можно заменить функциональный вызов с его итоговым значением, не меняя при этом значения программы.

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

Теперь сделаем паузу, выдохнем и вернемся к более понятным вещам, а именно, к разделяемым состояниям. Основная проблема разделяемых состояний — чтобы понимать эффекты функции, нужно знать всю историю каждой разделяемой переменной, которую использует функция. Поэтому функциональное программирование избегает разделяемых состояний, вместо этого полагаясь на неизменяемые структуры данных и чистые вычисления с целью извлечения новых данных из существующих. Еще один нюанс, который возникает при работе с разделяемыми состояниями — изменение порядка вызова функций может повлечь за собой лавину ошибок. Соответственно, избегая разделяемых состояний, вы также избегаете этой проблемы.

В основе всего функционального программирования лежит неизменность (immutability). И тут важно не путать const с неизменностью. const создает связывание имени переменной, которое не может быть переприсвоено после создания, но оно не создает неизменяемые объекты. Вы не сможете изменить объект, к которому относится связывание, но вы все еще сможете менять свойства этого объекта, соответственно, связывания, созданные const, не являются неизменяемыми. Неизменяемые объекты вообще не могут быть изменены. Это достигается глубокой заморозкой переменных.

И, если вы еще не совсем устали, на секунду рассмотрим побочные эффекты. Побочные эффекты означают, что помимо возврата значения функция также взаимодействует с внешним изменяемым состоянием. Почему ФП их избегает? Потому что таким образом эффекты программы гораздо легче понимать и тестировать. Haskell, к примеру, для изоляции побочных эффектов от чистых функций, использует монады.

Итак, ваша голова, скорее всего, начала побаливать, но обязательно найдется кто-то, кто спросит: так все-таки, почему декларативный, а не императивный подход? В чем соль?

Соль в том, что императивный подход работает по принципу управления потоком и отвечает на вопрос «как делать». Декларативный же подход описывает поток данных и отвечает на вопрос «что делать». Вдобавок, императивный код чаще всего использует инструкции (операторов), а декларативный больше полагается на выражения.

Итак, мы вроде бы разобрались с тем, что такое функциональное программирование и что нужно о нем знать. И, прежде чем мы перейдем к обсуждению его преимуществ, предлагаю сперва пройтись по недостаткам — точнее, вникнуть в суть стереотипа «функциональное программирование неестественно».

Чтобы написать код, станьте кодом

Судя по тому, что я писала выше, среди читателей уже должны были зародиться адепты функционального программирования. Тем не менее, несмотря на огромное количество хвалебных статей, находится не меньшее количество статей под названиями «Функциональное программирование странное и не имеет будущего» (к примеру). Означает ли это, что я заблуждаюсь? Нет. Есть ли причины считать ФП странным? Разумеется.

Позвольте приведу цитату, взятую с просторов Интернета, которая полностью отражает отношение многих разработчиков к ФП:

«Написание функционального кода — словно написание задом наперед и чаще всего похоже на разгадывание головоломки, а не на объяснение процесса компьютеру».

На самом деле, это довольно субъективное отношение к ФП тех, кто не хочет уделить достаточное количество времени тому, чтобы разобраться в нюансах функционального программирования и просто попробовать. Но, как я и обещала, разберем недостатки ФП, чтобы потом перейти к преимуществам.

Недостатки

Во-первых, для функциональных языков нет эффективного неупорядоченного словаря и множества. Чисто функциональные словари работают медленнее хэш-таблицы, и для некоторых приложений это может быть критично. Во-вторых, не существует чисто функциональных слабых хэш-таблиц, хотя для большинства разработчиков этот недостаток может остаться незамеченным.

Также ФП не подходит для алгоритмов на графах (за счет медленной работы) и в целом для тех решений, которые десятилетиями основывались на императивном программировании.

Ладно, последний пункт больше звучит как придирка — мы не можем винить ФП в том, для чего оно не было предназначено. Поэтому предлагаю обратиться к приятному, а именно — к преимуществам ФП и его использованию в реальных проектах реальными международными компаниями.

Преимущества

Один из самых явных плюсов функционального программирование — это высокоуровневые абстракции, которые скрывают большое количество подробностей таких рутинных операций, как, например, итерирование. За счет этого код получается короче, и, как следствие, гарантирует меньшее количество ошибок, которые могут быть допущены.

Далее, в ФП содержится меньшее количество языковых примитивов. Хорошо знакомые всем классы в ФП просто-напросто не используются: вместо создания уникального описания объекта с операциями в виде методов, в функциональном программировании используется несколько основных языковых примитивов, хорошо оптимизированных внутри.

Вдобавок, функциональное программирование позволяет разработчику приблизить язык к проблеме, а не наоборот, и все за счет гибких структур и пластичности языка. К тому же, ФП предлагает разработчикам новые инструменты для решения сложных задач, которыми ООП программисты зачастую пренебрегают.

На самом деле, перечислять все преимущества функционального программирования слишком долго — их правда много. Могу сказать так: работа с функциональными языками обеспечивает точное и быстрое написание кода, облегчает тестирование и отладку, программы более высокоуровневые, а сигнатуры функций более информативны.

Разумеется, нельзя отрицать преимущества ООП, но стоит помнить и о том, что функциональные языки по своему удобству стоят наравне со многими другими и достойны вашего внимания.

Гребень волны IT-трендов и применение ФП

В мире IT ничего не происходит просто так. Одно цепляется за другое, и вот уже все самые «горячие» тренды связаны между собой.

Если вспоминать наиболее нашумевшие тренды 2016-2017 года, это, разумеется, будут AI, IoT, Big Data и Blockchain. Они у всех на слуху, всем известен их потенциал и ключевые особенности. И именно некоторые из этих трендов послужили катализатором роста популярности функционального программирования среди разработчиков.

В настоящее время очень остро стоит проблема параллельной обработки и работы с большими потоками данных, другими словами, работа с Big Data. И, распараллелив обработку этих данных, можно получить желаемый результат за долю секунды, что очень критично в реальном мире. Плюс не забывайте о децентрализованных (распределенных) вычислениях — блокчейнах и других, которые, по сути своей, являются довольно сложным механизмом. И для таких вычислений функциональный код подходит больше всего за счет всех принципов функционального программирования (таких, как чистые функции, например). Использование всех базовых приемов ФП облегчает параллельное выполнение кода и его поддержку.

Вдобавок, если раньше функциональное программирование использовалось только для решения специфических задач, то теперь оно применяется даже на классических проектах. Из чего можно смело делать вывод: крупным IT — компаниям не стоит сомневаться по поводу использования функционального программирования, а в качестве примера можно привести один из проектов Intetics, на котором занимаются разработкой продвинутых Front-end приложений с интерактивным UI.

Суть проекта

Еще до того, как команда Intetics присоединилась к проекту, заказчик разработал собственный функциональный язык программирования. О причинах мы поговорим чуть позже, а пока что ответим на вопрос: почему именно функциональное программирование?

Суть проекта заключается в разработке системы адаптивного обучения для широкой аудитории: от образовательных учреждений до различных неакадемических курсов и предметов, как виноделие, теория игры в гольф и т. п. Еще один крупный сегмент проекта — корпоративное обучение, которое подразумевает разработку обучающего курса для специфичных нужд конкретной компании или организации.

Заказчик был не только инноватором (на тот момент это было первое подобное решение на рынке), но и весьма проницательным человеком. Он разглядел все достоинства функционального программирования раньше своих конкурентов, и это позволило ему обеспечивать высокое качество своего продукта и поддерживать его в соответствии с требованиями. То есть ФП обеспечивало лаконичность кода, плюс, подходило клиенту по стилю. Справедливости ради стоит сказать: ООП тоже подходит под решение задач проекта, и заказчик пробовал несколько языков, но выбор все же остановил на функциональном программировании.

Говоря о причинах разработки собственного языка, не забывайте, что мы говорим о проекте десятилетней давности. В то время не было достаточно развитых кроссплатформенных фреймворков, подходящих для данных задач, и поэтому заказчик просто взял и создал собственный — flow для быстрого создания UI под разные платформы. И это очень облегчает работу, позволяя быстро внедрять любые изменения и решать любые задачи, связанные с проектом. К тому же, кроссплатформенных функциональных языков очень мало, так что проект действительно выделяется среди своих аналогов.

Вывод — не бойтесь пробовать

Как вы уже наверняка поняли, функционального программирования опасаться не стоит. Немного усердия и любознательности, и вот вы уже освоили ФП. Вот несколько советов тем, кто решился попробовать себя в новом жанре и выучить что-то кардинально новое:

  • Расслабьтесь :) Поначалу и правда будет сложновато, учитывая, что вам придется отодвинуть на задний план то, что вы знаете, и учить новые подходы и принципы. И это нормально. Вспомните, как вы впервые учились кодить. Ничего страшного не случится.
  • Начинайте с микрозадач, чтобы «набить руку».
  • Начните изучать Haskell и затем переходите на Scala (или F#), чтобы начать вникать в принципы функционального программирования (а заодно начать мыслить более «функционально»).
  • Вам могут пригодиться эти ресурсы:
Учитывая распространенность функционального программирования, вы можете быть спокойны за свое профессиональное будущее (при должном усердии), так как наверняка сможете найти применение новоприобретенным навыкам. Не бойтесь пробовать!
LinkedIn

Лучшие комментарии пропустить

— Сынок, ты уже взрослый, пора нам поговорить о функциональном программировани.
— Хорошо, пап. Что ты хочешь узнать?

1) как обстоят дела с вливанием новых людей в команду?
2) как обстоят дела с поддержанием старого кода?
3) на что похож ваш функциональный язык?
4) у вас выработались какие-то best practise и code styles для вашего языка? что такое «красивый функцилнальный код» по вашему мнению?
5) было ли у вас чувство — а вот с этой задачей отлично бы справился ООП подход?
6) есть ли у вас метрики, что подтверждают "

высокое качество своего продукта и поддерживать его в соответствии с требованиями

" или это интуитивное чувство?
7) если бы вы писали проект с нуля сегодня — какой язык/платформу бы выбрали?
8) возникали ли вопросы с оптимизацией функционального кода?
спасибо

Для фронтенда, тем более функционального, js не нужен. Есть отличный функциональный язык Elm, который полностью спасает от джаваскриптовых заморочек.

— Но ведь она же ж красивая!
— Ну хорошо но потом сжечь!
(к)

100 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

ООП — это для тех кто не осилил в матан (на самом деле — общую алгебру).

Як кажуть, функціональний код круто писати, але неможливо читати.

Декілька разів вже зустрічав коли, намагаючись показати крутість функціонального підходу, показують лаконічний шматочок коду, який робить магію, але використовує 3-4 самописні функції високого порядку. В результаті, написаний код є, в певному сенсі, кодом на місцевому діалекті, який зразу і не прочитаєш.

З подібним я зіштовхувався лише в С/С++, коли люди програмують define-ами. Магія та потужна, але розібрати і віддебажити дуже важко.

В С/C++ Eclipse спокійно ті дефайни розгортає в кінцевий код, коли мишу наводиш

Можливо, я не до кінця відчув велику ідею. В простих випадках define-и не проблема. Але я згадую час, коли трохи доводилося працювати з MFC (древній microsoft-ський фреймворк під плюси). Тоді, ту маленьку задачу вирішити вдалося, але після того я старався триматися подалі від MFC і від складних define-ів) ... тим більше що вже появлявся .NET по трохи.

В ФП є два напрямки: динамічно типізований, для якого найважлива експресивність коду, і статично типізований, для якого важливіше здатність описати, що програма робить і дати компілятору перевірити, чи коректно це робиться.

І не дивіться на «лаконічні шматки коду»: вони часто дійсно сильно переускладнені. Це приблизно якби «крутість» імперативного програмування показували, для прикладу, через коротку реалізацію алгоритму dancing links Кнута: робиться магія, і стисло, але без спеціальної підготовки зрозуміти це неможливо.

Магія статично типізованих функціональних мов (того ж Хаскеля) у тому, що якщо задача гарно лягає на типи, то компілятор практично починає читати думки і вказувати на нетривіальні баги, і коли результат запускається, то працює майже завжди зразу.

Given software which just compiles, in Haskell you have a better chance of it working than in most other languages.

— Michael Snoyman aka @snoyberg

Ребятки, как завезут что-нибудь масштаба unreal engine, linux kernel, или хотя бы Facebook iOS на неизменяемых состояниях и чисто функциональных языках — звоните :)

Moe сугубо субъективное мнение — чистая функциональщина напоминает того накуренного математика из народной байки, доказавшего на 10 страниц мелким почерком теорему о том, что банан без кожуры меньше его же с кожурой. Чистое ООП — это анекдот про полностью автоматический девайс для бритья, в котором только первый раз все лица разной формы.

А вот мультипарадигменность — это отлично! Пусть ругаются пуристы — прагматикам пофиг. Scala, Kotlin, F#, та даже Ruby, свежие кресты и Objective C — годняк.

без коду нє очєнь. лірики багато зате.

Статья о программировании без единого примера. Вообще ни строчки кода. Очень тяжело читается...

Программист с отсутствием абстрактного мышления?)

Почему сразу «абстрактного»? ((

в принципе с отсутствием мышления? ))

Покажите, пожалуйста, учебник по шахматам без позиций и их разбора.

Как можно абстрактно представить, то вообще не понимаешь?
Это ж статья для тех, кто хочет познакомится с чем-то новым

Статья, чтобы побудить людей искать информацию о ФП.
Есть же достаточно большое количество статей из разряда, видите эту большую и свершенно нечитаемую простыни из ифов траев и кетчей? А теперь смотрите, как это умещается в 5 строчек через флет мап, свёртки и прочее.

Все равно, самый нечитаемый код у Седжвика — сортировочная сеть в 5 строчек

 (=<`#9]~6ZY32Vx/4Rs+0No-&Jk)"Fh}|Bcy?`=*z]Kw%oG4UUS0/@-ejc(:'8dc

— Но ведь она же ж красивая!
— Ну хорошо но потом сжечь!
(к)

мир так и не освоил ОПП. назад, к истокам, уря, товарищи.
как там говорится: сумма знаний константа, а население растет

Дик ООП не ідеал, має купу проблем, а з часом вони можуть множитися та ставати хронічними. Функціональне програмування теж не ідеал. Всі ці підходи вирішують гарно тільки одну, ну максимум дві задачі, все інше — біль та страждання.

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

ООП не може бути наступною сходинкою після ФП. Бо вони навіть не на одних сходах стоять.

нарисуйти иерархию, а то я запутался

Це як ссавці та птахи, наче й теплокровні обидва, але мають мало спільного в побудові.

Карочи «функциональное программирование» это не то которое «на простых функциях» а то которое «на чистых функциях» та штука об которой «в иерархии ооп» она зовётся по-научному «императивное программирование» и формально там сущность носит термин «подпрограмма».

не утверждал, что ооп идеал. но он все таки следующая ступень после фп.

Дядя, не путай процедурное программирование с функциональным

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

Вот откуда вы такие берётесь?
Отсутствие побочных эффектов у функции — только один из принципов ФП. Там основная фишка в stateless.

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

ну продолжайте верить в стейтлесс функции внутри программы

А можна з цього місця трохи детальніше... Ви про що зараз розповідаєте?

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

сайд-эффекта нет, то и какие вопросы?

вопрос один: откуда столько хайпа?

Ну как оказалось «а вот внутри» там ничего доброго уже нет одни только архитектурно имплементационные баги прямо на уровне процессорного ядра а что там между ядрами творится так вообще мало людей сказать могёт на самом деле хотя таки да им кажется якобы

а вот внутри...старый добрый си и или с++

прям так в песок и ссуть? тьху, на асме бутстрап и рантайм написан?

Хороший вопрос таки да я вдруг поймал себя на том что даже не задумывался а на чём собственно пишется сам микрокод самого центрального процессора... пичалько мне стыдно.

если самого самого, то на 42

Мікрокод процесора — конфіг. Там немає коду, тільки активація певних, вже закладених в «залізі», фіч. Як активація ДНК

Ну так всё развитие ЯП и сводится к тому чтобы упрятать как можно больше процессов под капот, и не заставлять програмиста воевать с языком, а решать задачу. В фп многие вещи очень хорошо прячутся под капот. Отсутствие состояния которое можно пощупать — однозначно большой плюс, о нём можно не думать, а думать вместо этого о чём — нибуть более полезном.

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

Нужен конкретный пример такого чиха, и то, насколько он значим в том плане что вставил кому — то палки в колёса. Кроме того, какая — то статистика возникновения таких чихов и невозможности их обойти малой кровью.

Нужен конкретный пример такого чиха

Система нормально работает, когда в ней одновременно отрабатывается 200 попугаев. При росте их количества до 300 загрузка удесятеряется, до 400 — увеличивается в сотни раз, всё встаёт колом.
Ежу понятно, что копать надо в поиске, где O(n^3) или что-то ещё столь же неэффективное, и где перестало вмещаться в кэш, но за 100500 слоями абстракций можно в принципе не добраться до нужного.

насколько он значим

Абсолютно значим: отказ сервиса.

Кроме того, какая — то статистика возникновения таких чихов

100%: они рано или поздно возникают.

невозможности их обойти малой кровью.

Невозможно, потому что неизвестно, куда именно лить эту кровь.

Слишком абстракный пример.
Кроме того есть большая разница между знанием того, что на сколько быстро работает и того, как именно оно написано.
Первое выучить гораздо проще, второе поголовно каждому знать не нужно.
Твой пример из первого разряда, и к теме статьи он притуливается как горбатый до стены.
Шла речь о том, что хорошо использовать ФП там где оно хорошо и сокращает код без удара в производительность. Кроме того большинство ФЯП имеют лазейки для императивного кода (например, скала отлично работает с дажвовским кодом, в хаскель подтянуть сишные либы можно).
Ясное дело что ровно в каждой технологии и архитектуре есть подводные камни о которых нужно помнить и знать. Используя функциональный подход, мы можем упростить себе жизнь, а не используя — мы забираем у себя такую возможность.

не используя — мы забираем у себя такую возможность

Тут еще вопрос в цене. Не используя — не платим цену (переобучение/поддержка кода, рантайм)

Шла речь о том, что хорошо использовать ФП там где оно хорошо и сокращает код без удара в производительность.

У меня «шла речь» о том, что предсказать, где именно ФП будет хорошо и «без удара в производительность», возможно далеко не всегда. А за счёт логики, которая не соответствует логике работы исполнителя, и слоя проекции, который нужен, чтобы «на этом» запустить что-то на ФП — задача сделать так, чтобы оно работало и успевало — становится сложнее, чем на ИП. В среднем, конечно. Но показанные цифры — близки к тому, что мы наблюдали на совершенно реальной задаче.

Используя функциональный подход, мы можем упростить себе жизнь, а не используя — мы забираем у себя такую возможность.

Если бы всё ограничивалось только этими общими словами, то говорить не о чем было бы вообще. Мы каждую секунду забираем у себя тысячи возможностей, но что-то мир пока не рухнул от этого, и явно не собирается.

Текущая ситуация такова, что ФП в полном виде (а не отдельные его элементы, в виде, например, map-filter-reduce или замыканий в большинстве современных ПЯП) требует выгиба мышления и затрат рантайма, которые далеко не всегда оправданы. А поддерживать это обычно сложнее.
Всё, что было просто и выгодно забрать из ФП в ИП, уже забрано. Остался чистый «матан».
Мне это тоже не совсем нравится.

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

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

Ваш пример легко допускается вне зависимости от парадигмы. Достаточно нанять идиота.

Мой пример всего лишь отражает то, что в ФП легче оторваться от земли и улететь в небеса. Уж поверьте писавшему на Erlang, LISP и даже чуть-чуть на m4 ;)

Компьютеры работают процедурно. Даже аппаратные LISP-машины работают процедурно. В переходе от ФП к императивщине всегда есть уровень, где логика верхнего уровня укладывается, выгинаясь в неожиданные формы и разламываясь от этого, для того, чтобы уложить на императивную прозу из ячеек памяти. В этом случае стать таким идиотом в разы легче, чем на любом ИП. Я сам им становился не раз ;)

Давайте какую-нибудь реальную задачу. Не связанную с системным программированием

А где вы проводите границу между системным и прикладным программированием?
Является ли для вас «системным программированием», например, задача построения атрибутов «объектов» — листов дерева, при том, что атрибуты могут наследоваться от родителей, вплоть до корня дерева, самих атрибутов около 50, а в типичном дереве 5-8 уровней, и всё это на скорости (в идеале — несколько тысяч раз в секунду на мелкосерверном процессоре)?
Или задача манипулирования свойствами долгоживущих объектов в количестве около сотни тысяч, делая выводы по правилам, впрыснутым в систему в виде DSL, с требованием минимизировать изменение структур в памяти, ибо иначе GC не успевает?
Заметьте, никаких прямых лазаний к железу, запусков процессов, и даже GUI нет. Это системное программирование (для вас) или прикладное?
(Зато задачи 100% реальные, просто из прошлой практики.)

ибо там ФП пока что не очень осмысленно применять

А где его, по-вашему, осмысленно применять? Вы хотите реальных примеров — так дайте свои.

Во, это уже больше похоже на дельный разговор. Вы уже делитесь своими задачами, вашим контекстом.

Давайте я уточню получше область, где ФП лучше не применять.

Задачи, в которых мы упираемся в ЦПУ — вот здесь лучше не лезть со всякой шнягой типа ФП, GC и прочим. Так, к примеру, в C# большинство людей понимают, что простое переписывание LINQ на foreach может дать 2x-4x в производительности.

Но только не везде эта производительность нужна. А вот выразительность нужна везде. ФП дает выразительность в некоторых задачах. Но это не zero-cost абстракция. Она имеет цену. Когда у вас накладные расходы на ФП достоточно малы для вас, то заменять ФП на что-то другое будет микрооптимизацией.

И я как-бы очень рад, что у вас есть performance critical задачи. Но есть куча областей, где их нет. Если для ваших задач что-то не подходит, то это не значит, что это что-то является бесполезной хуетой. То, что вы не видите задач, где ФП рулит скорее всего следство вашей специализации на performance critical задачах.

Теперь, о том, как мне помогает ФП. Задачи трансформации/обработки данных очень легко выражаются через map/filter/flatMap/toDictionary и тому подобное. И императивный код зачастую у меня занимает больше строк и менее понятен, чем ФП-подобный. Если я вижу проседание производительности из-за неэффективности ФП, то я делаю фоллбек на более низкий уровень.

И дополнительно: я не использую ФП как клей в масштабе всего проекта. У меня ФП является локальной оптимизацией выразительности, которая помогает сжать кучу кода до понимаемых размеров.

Соответственно, если снять с ваших примеров ограничения по performance, то ФП может рулить и бибикать за счет выразительности. Но в вашем случае это недоступно. Это не значит, что инструмент плохой. Он не подходит под вашу задачу.

GC и прочим

А вот тут обидно было.

Соответственно, если снять с ваших примеров ограничения по performance, то ФП может рулить и бибикать за счет выразительности.

У вас какое-то очень простое, «домашнее» ФП. Многие адепты с этим не согласятся — я имею в виду тех, для кого Haskell это минимальный уровень языка.

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

Я не вижу особого смысла в задрачивании на чистое ФП вне академических областей. В практической области можно и нужно подбирать инструменты под задачу. Цель ведь создать что-то полезное, а не писать код ради кода.

Или вы считаете, что для защиты ФП нужно упарываться концепцией по самые гланды?

Кстати. LISPы же всегда славились своей практичностью. Они ориентированы на иммутабельность+ФП, но дают возможность писать код и в императивном стиле, и в ООП. Вопрос: вы пользовались этой возможностью или оставались в рамках полной чистоты?

А вы меньше слушайте фанатиков. Фанатики по обе стороны ***нутые.

1. Насколько я помню, мат тут не приветствуется. Рекомендую исправить сразу.
2. И как их отделять, если те, кого вы назвали фанатиками, составляют >90% источников шума про ФП?

Или вы считаете, что для защиты ФП нужно упарываться концепцией по самые гланды?

Я считаю, что те, кого вы назвали фанатиками, таки представляют собой наиболее заинтересованных в том, что является настоящим ФП. Это независимо от того, насколько их результаты пригодны для «ширнармасс».

Кстати. LISPы же всегда славились своей практичностью. Они ориентированы на иммутабельность+ФП, но дают возможность писать код и в императивном стиле, и в ООП. Вопрос: вы пользовались этой возможностью или оставались в рамках полной чистоты?

Пользовались.

GC — чего обидного-то? Абстракция GC часто протекает (как и другие абстракции).

GC — чего обидного-то?

В связывании GC с тормозами исполнения.

то что процедуру назвали функцией ничего не меняет, только процедурное программирование — это подраздел императивной парадигмы, а функциональное — декларативной, ну а императивная и декларативная парадигмы противоположны

Гм. Вы умудряетесь спорить о вещах, о которых не имеете ни малейшего понятия.

Во-первых, ООП не может быть следующей ступенью ФП, потому что «объекты — замыкания для бедных, замыкания — это объекты для бедных». Задание «написать свое ООП» является вводным для многих курсов по ФП.

Во-вторых, ваша идея о том, что процедурное программирование == функциональному страдает двумя болячками. Болячка первая: в ФП как-ни странно не функции, а замыкания (функция + захват переменных). Без замыканий, на чистых функциях нельзя получить мощь аналогичную ООП. Болячка вторая: процедуры нельзя легко передавать в другие процедуры. Что делает невозможным high-order functions. А high-order functions позволяют выразить как минимум 1/3 (мне лень считать) паттернов GoF. То, что вы в старом добром С могли передать ссылку на метод — это неудобная ерунда, которая убивает легкость ФП.

В-третьих, ООП и ФП можно смешивать, они не мешают друг другу на самом деле (если не вдаваться в экстремизм). Поэтому ООП и ФП реально таки являются параллельными ветками развития.

Почему возник хайп вокруг ФП? То, что вы видите в мейнстриме — это не хайп. Это уже опробованные инструменты, которые перетекли из академичных разработок в практичные сферы. Просто ФП позволяет некоторые задачи решать проще (но некоторые на нем решаются сложнее).

о, что вы в старом добром С могли передать ссылку на метод — это неудобная ерунда, которая убивает легкость ФП

сперва ваша речь речь казалась умнее (несмотря на обилие штампов), но это....

В чем проблема-то? Вы же не хотите сказать, что в языке незаточенном под ФП так же легко работать с функциями как в языке заточенном под ФП? (Я подразумеваю, что вы знаете, что и в C, и в C++ можно передавать ссылки на функции, иначе было бы вообще глупо). Или вас смущает отсылка к C, а не к современным C++, в котором более-менее зарождается ФП?

А со штампами в чем проблема? Если аргументация типичная, но корректная, то это збс аргументация, нет?

проблемы две:
1. неудобная
2. ерунда

да, это немного трики, и можно отстрелить себе все, что угодно и тд и тп, но основная фича Си — не облегчить жизнь разработчику, а получить максимально быстрый код

А основая фича ФП — решить задачу ясно и малым количеством строк кода. Естественно, это не будет идеально подходить для всех нужд. И соответственно, си и фп друг на друга довольно плохо натягиваются.

Или вас смущает существование областей, в которых не нужно выдрачивать код?

Как для PR-менеджера (www.linkedin.com/...​in/irina-linnik-35970554), то вы сделали Интетикс медвежью услугу. Ну а как копирайтер написали еще и тяжелый текст. Так вы слона не продадите :)

Слонов продают немного по-другому :) Спасибо кстати, что напомнили обновить мой профиль. Если есть еще какие-то сомнения, смело пишите мне в личные сообщения)

И буду рада услышать, как писать тексты «полегче», все же копирайтер во мне жив, и в целом для работы будет полезно узнать. Мало ли еще каких слонов подвезут на продажу.

буду рада услышать, как писать тексты «полегче», все же копирайтер во мне жив

А почитайте мои статьи :) У одной 110000 просмотров, у другой 60000. Более того, статью на интересующую вас тему у меня можно даже заказать. Более того, уже заказывают и довольны :)

С удовольствием гляну, спасибо)

Я бы эту вашу статью переписал по другому. С реальными преимуществами функционального подхода и плюсами этого вашего flow для специалистов.
Поймите, вам надо так чтобы люди прочитали и аж загорелись:"Вау, какая крутая штука. С ней интересно работать".

Можно еще мою лекцию смотреть. Лямбда исчисление и функциональное программирование. youtu.be/dowYB_dPkmU

— Сынок, ты уже взрослый, пора нам поговорить о функциональном программировани.
— Хорошо, пап. Что ты хочешь узнать?

Вышеописанные примеры неэффективной работы относятся исключительно к чистым ФП языкам (как Хаскель). Скажем, на той же Скале таких ограничений нет. И вообще, проблема хоть и есть, но достаточно переоценена — читать www.cs.cmu.edu/~rwh/theses/okasaki.pdf для деталей. Для большинства императивных алгоритмов существуют чисто функциональных аналоги с той же асимптотической сложностью времени работы.

Ничто не мешает писать на Haskell императивно там, где надо, вплоть до использования указателей. Но чаще всего подобные оптимизации не критичны, а если и нужны — их лучше инкапсулировать, отделяя от безопасного кода.

И в итоге получим неидиоматичный лапшехаскель. Не зря в определенных узких кругах есть мемы «монадный бейсик» и «телебейсик».

А никто не просит по проекту размазывать. Всяко выглядит лучше, чем монады на плюсах.

Для фронтенда, тем более функционального, js не нужен. Есть отличный функциональный язык Elm, который полностью спасает от джаваскриптовых заморочек.

Есть опыт применения Elm в боевом продукте? опять таки волнует вопрос переучивания/интеграции разработчиков на функциональную парадигму

Только во внутреннем, для разработчиков. В том, что отдаем заказчику фронтеты написан достаточно давно, а интергироваться в существующий js оказалось слишком сложно. Собираемся новое на Elm делать, но пока все задачи по поддержке старого.
Внутреннее пишу я, хоть я и бэкендер. Фронтендеры мне с версткой только помогают — Elm-код они вполне хорошо воспринимают, несмотря на отсутствие опыта.

А чому не PureScript? Elm доволі порізаний, нема higher-rank types, higher-kinded types, typeclasses. Плюс Elm-у в тому, що він простий.

В Elm реализован очень приятный подход model-updater-view, который позволяет забыть об DOM и джаваскрипте, как о страшном сне. PureScript от этого мусора пока не изолирует.
Я планирую применить PureScript в AWS Lambda (сервис для serverless-приложений от Амазон), но пока руки не дошли. Ранее я писал AWS Lambda на Scala, но у него слишком долгий холодный старт — до 30 секунд, а у ноды не больше 6-7.

интересно будет узнать сколько старт у PureScript
а то нода оказывается жутко резвой)

чем тогда питон плох?

Всем.
Нет статической типизации, плохая поддержка ФП, не слишком удобный синтаксис. Да и холодный старт в среднем на пару секунд дольше, чем у ноды.

У AWS Lambda всегда длинный холодный старт, это by design. Самый короткий кстати в Go, который две недели назад вышел.

У jvm он длинный, даже по сравнению со всеми остальными.
Go мне не нравится — он не функциональный и соглашения о возврате ошибок там идиотские. Думаю, что PureScript нам хватит.

Также ФП не подходит для алгоритмов на графах (за счет медленной работы) и в целом для тех решений, которые десятилетиями основывались на императивном программировании.

На кого рассчитана эта статья?..

А что не так? Как вы сделаете алгоритм Дейкстры функционально?

Эмм... воообще то алгоритмы поиска пути на графах только с помощью функционального подхода и делаются

В функциональном стиле всекие пометки вершин и ребер приходится таскать за собой в отдельных структурах данных, а в императивном — можно хранить в самом графе. Хотя отделение пометок от графа иногда удобнее и обычно делает код понятнее, снижает эффективность.

Просто структуры данных надо грамотные использовать. Пройди курс одерски «функциональное программирование». Сразу станет всё понятно

На студиозов, которых хотят заманить на проект с flow — язык, который заточен под конкретного заказчика, а значит бесперспективен для дальнейшей карьеры. Там ещё и два тестовых сделать нужно

Мне так говорили, когда предлагали эту вакансию. На сколько я знаю, проект раньше в другой конторе был.

На студиозов, которых хотят заманить на проект с flow — язык, который заточен под конкретного заказчика

Если речь про вот этот Flow: flow.org, то я бы не сказал, что он заточен под конкретного заказчика (хотя в последнее время и сдаёт позиции TypeScript’у).

Только вот я не понял, какое отношение Flow имеет к функциональному программированию?..

то я бы не сказал, что он заточен под конкретного заказчика (хотя в последнее время и сдаёт позиции TypeScript’у).

Это вроде не он.

1) как обстоят дела с вливанием новых людей в команду?
2) как обстоят дела с поддержанием старого кода?
3) на что похож ваш функциональный язык?
4) у вас выработались какие-то best practise и code styles для вашего языка? что такое «красивый функцилнальный код» по вашему мнению?
5) было ли у вас чувство — а вот с этой задачей отлично бы справился ООП подход?
6) есть ли у вас метрики, что подтверждают "

высокое качество своего продукта и поддерживать его в соответствии с требованиями

" или это интуитивное чувство?
7) если бы вы писали проект с нуля сегодня — какой язык/платформу бы выбрали?
8) возникали ли вопросы с оптимизацией функционального кода?
спасибо

было ли у вас чувство — а вот с этой задачей отлично бы справился ООП подход?

Ни разу.

Юрий — возможно вы не совсем полностью овладели ООП? Вы хотите об этом поговорить?

Овладевание ООП разлагает. Полное овладевание ООП разлагает полностью. Если долго овладевать ООП, ООП может овладеть вами.

те по вашему все єто ООП зло? И его просто очень удобно впаривать неокрепшим умам топ-менеджеров? те все о чем написано столько книг, фреймворков, семинаров, мультиков — все это блажь, ложь, и мираж? неужели вы намекаете на то, что нас всех развели?

Заметьте, не я это сказал. Наше дело маленькое: действовать по обстоятельствам и не вестись на провокации по чём зря.

1) как обстоят дела с вливанием новых людей в команду?

А з цим хоч раз були проблеми?

1) как обстоят дела с вливанием новых людей в команду?
Есть тренинги, есть обучение — обычно все довольно быстро вникают в суть. В команде много творческих людей, к слову — так что работается, как минимум, интересно.

2) как обстоят дела с поддержанием старого кода?
Хорошо :) Мы же постоянно его дорабатываем и совершенствуем — уже больше 10 лет проекту как-никак.
Стараемся переводить старых клиентов на последнюю версию используемой платформы. Но, конечно, поддержки legacy кода не избежать. Стоит отметить, что большая часть людей задействована на новых проектах.

3) на что похож ваш функциональный язык?
Standard ML, O’Caml и F#. И немного на Haskell и Scala.

4) у вас выработались какие-то best practise и code styles для вашего языка? что такое «красивый функцилнальный код» по вашему мнению?
Безусловно. Более того некоторые (не все) правила интегрированы прямо в компилятор. Т.о. он просто не даст разработчику скомпилировать явный говнокод :)

5) было ли у вас чувство — а вот с этой задачей отлично бы справился ООП подход?
Конечно. Я больше скажу — для некоторых специфичных задач используется не только функциональный язык программирования, но и другие, более меинстримовые, в том числе и ООП языки.

6) вопрос по метрикам
Есть. В первую очередь, фидбэк клиента и пользователей :)

7) если бы вы писали проект с нуля сегодня — какой язык/платформу бы выбрали?
Сложный вопрос.
Во-первых на сегодня в нашем распоряжении есть не только ЯП, но и целая платформа разработки с библиотеками UI компонент, клиент-серверного взаимодействия, и т.д.
Во-вторых мы до сих пор не видим на рынке полноценной кроссплатформенной технологии, которая бы удовлетворяла всем нашим нуждам, а уж тем более построенной на функциональном языке. Напомню, у нас в арсенале есть компиляторы, которые позволяют получать нативный бинарный код для iOS, Android, Windows, а также веб версию (HTML + JS).

8) возникали ли вопросы с оптимизацией функционального кода?
Да, конечно. Реальные кейсы с реальных проектов позволяют обнаруживать bottleneck’и. Стараемся решать их силами нашей platforms team, оптмизируя код «внутри» самого языка программирования.

Подписаться на комментарии