Привет, меня зовут Марат Зимнуров и я тимлид в кросс-функциональной команде HR Admin Tech Авито. Наверняка, вы уже сталкивались с термином «функциональное программирование» (ФП). Если посмотреть на популярные доклады (например, на HolyJS), тема функционального программирования раскрыта довольно поверхностно: immutable-структуры, transitions — и всё. В русскоязычном сегменте нет нормального baseline-гайда, с которого можно начать, да и в англоязычном ситуация не лучше: пара разрозненных курсов и несколько докладов про иммутабельность и монады от хаскелиста.

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

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

Кстати, на изображениях внутри вы найдёте QR-коды с дополнительной информацией по теме.

О чём статья?

Математическая основа ФП

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

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

Но давайте попробуем упростить это для нашего мира, где мы ежедневно программируем на JavaScript, TypeScript или любом другом языке. Как применить теоркат и запомнить его основы? Начнем с понятия функтора. Это базовая идея: у вас есть данные, и к ним можно применить функцию map — классическую функцию, которая проходит через каждый элемент и может что-то с ним сделать. Это немного напоминает Data-Oriented Programming, но идет дальше и глубже.

В результате вы получаете полезную схему, которую можно найти в интернете — её много обсуждали на Хабре и легко найти в Google. Я хочу дать вам практический инструмент. 

Например, хотите понять, что такое монада

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

Затем нужно понять apply — помните вопросы на собеседованиях про apply, bind, call и их различия? Вот мы добрались до apply-функтора. Что дальше?

А дальше у нас chain-функтор. Что такое chain? Цепочка, верно. Когда вы начинаете искать информацию в интернете, читать книги по математике — вы узнаете, что это способ, например, из сущности Пользователь извлечь Имя, просто сменив уровень абстракции. 

Если совсем упростить — вы уже близки к пониманию монады. Но важно знать также истоки монад и происхождение идеи контекстов.

Теперь про инкапсуляцию. Лет пять назад на YT-канале ExtremeCode вышло видео про то, что «вы неправильно понимаете инкапсуляцию» — многие тогда действительно неправильно поняли и стали с пеной у рта доказывать, что инкапсуляция — это не сокрытие, именно потому, что насмотрелись таких вот роликов.

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

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

Таким образом, если кратко описать основные понятия, у вас есть базовое понятие функтора с функцией map, closure для создания контекста, applicative-функторы для операций над функциями-замыканиями и chain для распаковки данных. Теперь мы готовы определить монаду. 

Тут еще больше контента

Монада

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

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

Посмотрим наглядный пример.

Слева bro, справа не bro. Just enough. Если код читается вертикально, как говорил Боб Мартин в «Чистом коде», при рефакторинге класса Date на 200 страниц, то это хорошо. Справа же — хаос. Если вы любите недетерминизм, отладку на работе, чтение кода по диагонали — вы возвращаетесь к концепции goto, вместо декларативщины. Безусловно, интересно читать книгу и постоянно перелистывать странички назад, но понятнее читать её последовательно.

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

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

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

Так мы приходим к теории автоматов — ещё одному разделу математики.

Автоматы Милли, автоматы Мура, абстрактные автоматы и прочие — всё это может казаться непонятным. И это нормально. В функциональном программировании вы, по сути, просто переключаете состояния. У вас есть набор функторов, с помощью которых вы преобразуете одну структуру данных в другую на уровне типов. Это работает. Переменные вам не нужны.

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

Но думаете ли вы, что работаете с нулями и единицами? На этом обычно всё и заканчивается. Когда вас спрашивают «что такое программирование?», вы отвечаете: «Ну, я пишу что-то на каком-то языке, и потом это превращается в нули и единицы». Но куда понятнее объяснить обычному человеку так: «Я просто делаю так, чтобы мой код управлял электричеством». 

И тут вы чувствуете что-то возвышенное — это нормально.

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

Эволюция кода

Были цифры от персидского математика Аль-Хорезми. Эти цифры сами по себе ничего не хранят — мы просто пишем их на бумаге, они выполняют декларативную функцию. Потом появился Аристотель с его силлогизмами, где «Сократ должен умереть». Эту историю многие слышали на курсе логики в университете. Затем появилась алгебра логики, которую разрабатывали более полутора тысяч лет — то, что мы называем сейчас булевой алгеброй. Она тоже ничего не хранит, это декларативный стиль. Потом Морзе создаёт телеграф, позволяющий передавать электрические сигналы по проводам. А затем происходит нечто удивительное: Тьюринг создаёт первый компьютер с хранимой в памяти и исполняемой программой.

Как же появилось само понятие хранения данных? И правильным ли путём мы пошли, создавая современную разработку? Когда вы поймёте историю и основы теории категорий, вы сможете связать всё воедино и выработать более структурированное мышление. Давайте углубимся в историю.

У Тьюринга был супервайзер. Супервайзер — потому что он осуществлял надзор, supervision, то есть видел что-то большее. И часто ученики перенимают идеи своих учителей и научных руководителей. Так было и с Тьюрингом. Его руководителем был Алонзо Чёрч. Имена можно не запоминать, важно знать: есть Тьюринг и есть Чёрч. Что же сделали эти два гения, внёсшие огромный вклад в computer science и информатику?

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

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

Сравнивая императивный и декларативный подходы, возьмём HTML и CSS — что из них язык программирования? Это популярный предмет для споров. Некоторые обсуждают эту тему. Есть те, кто считает HTML языком программирования — и это нормально, давайте разберёмся. CSS действительно является языком программирования. Но почему? Задумайтесь, как вы определяете, что одно — язык программирования, а другое — нет? Здесь важна концепция полноты по Тьюрингу из императивного мира. Чёрч создал концепцию типизированной и нетипизированной лямбды. Мы её разберём позже, не волнуйтесь. HTML имеет определённый набор термов (типов) — это как конструктор с определёнными деталями, из которых можно собрать статичную структуру. CSS тоже имеет набор термов, но может создавать циклы, бесконечные последовательности или прерывания — это и есть, в нашем случае, полнота по Тьюрингу.

Оба инструмента являются типизированными лямбдами, потому что имеют фиксированный набор ключей. JavaScript — это нетипизированная лямбда, позволяющая создавать неограниченные структуры данных, а TypeScript — скорее типизированная лямбда. На HTML можно создать детерминированный конечный автомат: настроить множество файлов и связать их условными переходами через гиперссылки, даже создать рекурсию с помощью iframe. CSS полон по Тьюрингу — это язык общего назначения. 

Добавьте немного синтаксического сахара, и вы сможете делать на нём что угодно. С HTML ситуация иная: он не работает автономно в одном файле, вы не можете реализовать в нём полноценное императивное программирование с циклами, условиями и хранением переменных.

Декларативный подход

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

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

Углубимся в более понятные определения. Когда мы говорим о ФП против объектно-ориентированного программирования, возникает вопрос: что является примитивом? В ФП примитив — это функция, но как же тогда работать с числами? Чёрч предложил элегантное решение. Числа не нужно хранить в компьютере. Когда вы пишете 2 + 2 на бумаге, бумага просто отображает выражение, но не хранит его — она как экран.

Числа можно реализовать через функции. Достаточно определить 0, единицу и несколько правил. Вызывая функцию определённое количество раз, вы получаете числа: один вызов — число 1, ещё вызов — число 2, и так далее. Числа существуют в рантайме, их не нужно записывать в константы.

А как проводить математические операции? Сложение, деление, умножение? Всё решается вложением функций друг в друга (монады, привет!). Это похоже на школьную математику с функциями f(x) и g(x), которые многим казались непонятными.

Теперь о логике. Как построить логические операции, когда у вас есть только функции? Как получить true и false? Решение элегантное: создаём функтор с двумя аргументами, x и y. Для true возвращаем x, для false — y. Так мы вычисляем значения на лету.

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

Возьмём классический пример — вычисление факториала. Y-комбинатор можно определить в удобном стиле, реализовать функцию факториала без имён, и всё работает. Для простоты используются единицы, чтобы показать принцип работы факториала. 

По ссылке множество примеров перформанса этого решения.

Допустим, вы готовы пойти дальше и реализовывать что-то «пострашнее». На сайте ИТМО есть отличные примеры, включая реализацию факториала в «ниндзя-стиле» — всё в одну строку. Lambda Calculus. Это работает на бумаге, как и задумывал Чёрч. Если в конце поставить число — реализуется алгоритм вычисления. 

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

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

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

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

Условия применения ФП на практике

Когда же мы применяем ФП на практике? Обычно при рефакторинге, когда код становится «грязным» и нужны чистые функции. Почему они называются «чистыми»? Не потому что они красивые (иначе они назывались бы «beauty/beautiful functions»). 

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

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

Если мы переместим первый пример в другое место и применим к нему параллелизм, вывод будет разным. Со вторым примером такого не произойдёт. Это позволяет легко переносить код и применять его в разных местах.

Однако, при рефакторинге возникает вопрос: стоит ли выносить сумму двух чисел в отдельный литерал? Ответ на этот вопрос зависит от логики программы. Если логика хорошо продумана и контексты не меняются, то можно оставить сумму в сумме. Но если логика не соответствует новым условиям, то лучше её вынести.

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

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

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

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

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

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

Если задуматься, в архитектуре разработки существует идея event driven design и event driven development. Но когда вы работаете, скажем, с JavaScript, у вас нет полноценного multi-threading. Это реальность.

А как бы выглядел EDD с обработкой событий, теоркатом и lambda calculus? 

Вспомните, как в CS 1.6 мы подключались к игре: открыли список серверов, выбрали, подключились — всё, вы уже в моменте, играете. Сейчас же в современных играх вроде CS:GO добавили систему очередей: вы ждёте, пока сервер подберёт подходящий матч.

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

Логика остаётся прежней. Вам не нужно мгновенно получать обратную связь. Вы её в жизни не получаете. У вас есть только delay — возможность отправить запрос, но не получить ответ. Что-то всегда возникает между запросом и ответом.

Мы пытаемся сделать процесс похожим на реальность, но не учитываем, что иногда мы его не видим. 

Мы можем усложнить эту идею. У нас нет системы очередей, мы просто делаем пару выстрелов, и кто-то рандомно на карте получает хэдшот. 

Что объединяет эти два способа применения ФП, теорката и lambda calculus идей к обычной игре, мультиплеер-клиент-сервер или peer-to-peer, как хотите? У вас есть гарантия исполнения: и в том и другом случае вы получите какой-то ответ. Как его отследить?

Для этого существуют паттерны. Есть такая вещь, как distribution logging — распределённое логирование. Если говорить просто, вы присваиваете каждому шагу (экшену) уникальный идентификатор. В Redux вы привыкли присваивать разные экшены: экшентайпы, экшенеймы, как хотите. Но если вы используете один UID, то теперь ивент, отправившийся, к примеру, в HR-тех: кандидат пришёл на интервью, загрузил какие-то документы, CV, кандидата пригласили на техническое интервью, он его прошёл, не прошёл, по нему дали фидбек, затем он там онбордается, загружает свои доки и так далее.

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

Как ФП упрощает жизнь

ФП помогает упростить процессы. Например, AWS Lambda взяли простую идею: каждая функция — это отдельный Node.js процесс. Такой подход позволяет решать задачи, следуя теории минимальных частей.

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

Вот почему компании вроде Сбера, МТС и Яндекса внедряют эту систему (Functions): они упрощают тестирование, позволяют быстро адаптироваться и облегчают масштабирование.

Раньше мы использовали громоздкие подходы к тестированию: полный coverage и фреймворки/библиотеки вроде Cucumber, Cypress или Playwright. Это требовало времени, ресурсов и инфраструктуры, хотя можно написать кучу небольших юнит-тестов. 

Интересный подход предложил Дэн Абрамов на конференции We Are Developers. В его выступлении читалась мысль, что, вероятно, мы прошли круг в 30 лет и, создав server components, снова сделали PHP. Не знаю, закладывал ли он эту идею и писал ли об этом кто-то, но покопавшись в sandbox я понял одно: серверные компоненты позволяют обмениваться функциями.

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

React — это тот самый HTML, который стал языком программирования, где элементы визуально представляют собой функции, описанные names. Вы компонуете и декомпонуете интерфейсы, следуя простой идее: «Сделай одно или другое». Разумеется сохраняя базовые принципы.

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

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

Что происходит на 14 строке? Вы что-то где-то отрабатываете. Вы получили dynamo в виде базы, имя таблицы, идентификатор события — и поехали с ним работать. Либо пользователь что-то запросил, либо он что-то сделал. 

И вот ваш функтор. Это просто последовательность. Вы просто отрабатываете. 

Если вы будете читать этот текст: мне надо порезать полезную нагрузку, создать ее получение, отправить в базу, вытащить оттуда элемент, апстрингифайить и получить валидный статус. А если что-то пойдет не так — давайте вернем негативный статус. Все. На любом из этих шагов. 

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

Это всё потому что в какой-то момент код превращается в Haskell или Rust. Где все, чем вы занимаетесь — TDD  (type driven development). Все, что вы делаете — это пишете типы. 

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

То же самое: вы просто берете какие-то данные от пользователя, ничего никуда не сохраняя, вычисляете их на лету. Потому что компьютер от слова «вычислять» — compute. Это не калькулятор, не сохранятор. Даже в двоичный сумматор вы не можете что-то сохранить. Вы просто вычисляете. Это дорого с точки зрения перформанса на данный момент. Но в определенных пиках вы можете достигнуть хороших показателей и результатов. 

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

Вы позволяете падать вашим сервисам (даже если сервисы дохнут как мухи), потому что можете на каждом этапе теперь это отхендлить, потому что у вас есть всякие идеи типа EDD, distribution logging. Вы можете обмениваться базой данной с клиента на сервере — получите прикольную идею DEFI.

Здесь собрана огромная портянка разных JS методов. Можете их почитать, больше залезть в историю, практические примеры, что-то копипастить. 

Кликни здесь и узнаешь

Итоги 

Итак, вы должны задать себе финальный вопрос. А что такое ФП?

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

Что думаете о функциональном программировании? Пишите в комментариях.

А если хотите вместе с нами помогать людям и бизнесу через технологии — присоединяйтесь к командам. Свежие вакансии есть на нашем карьерном сайте.

Комментарии (26)


  1. Dhwtj
    11.07.2025 15:38

    Функциональное программирование основано на отрицании времени.

    Только возможные факты и правила их соответствия. Правила дают гарантии ещё до запуска программы.

    Когда эта мантра будет усвоена дальнейшее изучение ФП станет легче

    Из практических соображений имеет смысл не отрицание (как в Haskell), а вытеснение его наружу в эффектные слои, которые соприкасаются с миром, выполняют конкретные use cases, привязанные к контексту. И всё же, мы стараемся проверить правила ещё до запуска, ведь чем позже проверка, тем дороже ошибка, поэтому максимально «заталкиваем» проверки вверх по цепочке, остальное страхуем тестами и мониторингом.

    Императивное программирование можно противопоставить ему. Ещё нет правил, но уже есть желание дойти до цели. Умный командир, глупые исполнители. Такой стиль провоцирует что командир занимается не своим делом, а разбирает проблемы исполнителей на лету в зависимости от контекста и без гарантий.

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


    1. IUIUIUIUIUIUIUI
      11.07.2025 15:38

      Из практических соображений имеет смысл не отрицание (как в Haskell)

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

      эффектные слои


    1. CrazyOpossum
      11.07.2025 15:38

      Из практических соображений имеет смысл не отрицание (как в Haskell)

      В Хаскеле всё красивее. Есть тривиальная монада State, которая позволяет читать и писать контекст. А Хаскельная IO, в которой крутятся эффекты - это просто State, с контекстом #RealWorld. То есть, ввод с клавиатуры, сигналы, вызовы fopen, fread, fwrite, время и прочее и прочее - это просто контекст.


  1. asatost
    11.07.2025 15:38

    Очередная статья на хабре на тему "Что такое ФП". Если честно, ни из одной из них я так и не понял, что такое ФП и чем оно принципиально отличается от императивного foo(bar(arg)) или, как вариант, ООП-шного getFoo().bar().baz().

    В русскоязычном сегменте нет нормального baseline-гайда

    Потому что в русском языке нет слова baseline?


    1. Dhwtj
      11.07.2025 15:38

      императивного foo(bar(arg)) 

      Почему ты решил, что оно императивное?)


      1. asatost
        11.07.2025 15:38

        Почему ты решил, что оно императивное?)

        Потому что GOSUB в Бейсике был уже лет 40 назад.


        1. aamonster
          11.07.2025 15:38

          Ага, и те же 40 лет назад в бейсиковских подпрограммах не было способа вернуть результат :-). Всё, что можно – это изменять (мутировать) состояние. Даже стека для локальных переменных не было – только для адресов возврата.


    1. ApxuTechTop
      11.07.2025 15:38

      Реально, очередная статья рассказывающая сложно о простом в перемешку с каким то бредом. Люди придумывают себе концепции чтобы загонять себя в их рамки и решать проблемы которые они же и создают. Вместо foo(bar(arg)) или по нормальному const b = bar(arg); const f = foo(b) они хотят писать arg.map(bar).map(foo). Для разных задач лучше подходят разные концепции, функциональщина действительно хорошо подходит для работы с потоками данных. Также не стоит забывать что для использования функциональщины в не предназначенных для этого языках необходимо сначала написать вспомогательный код, который накладывает дополнительные расходы и может оказаться трудно поддерживаемым. В общем, нормально делай нормально будет


      1. CrazyOpossum
        11.07.2025 15:38

        Оба неправы, ФП - это не map/reduce/filter, и операторы через точку; автор пишет как раз о правильных вещах. Один из аспектов ФП - это найти в поведении данных математику и, доказав её, защититься от связанных ошибок. А ещё от ФП до ЯОП один шаг.

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

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