Pull to refresh

Comments 113

Очень странное определение категории. Морфизмы в катеориях это не всегда функции. И определенных правил всего три: Существование композиции, существование единицы и ассоциативность композиции.
Тут вообще очень много странных определений
Если реально хотите понять про ФП, то лучше почитайте книги о Haskell. Из русскоязычного настоятельно рекомендую http://anton-k.github.io/ru-haskell-book/book/toc.html тут и про ФП и про ТК есть отчасти достаточно интуитивно понятно (вообще это наверное лучшее, что я читал из бесплатных онлайн книг на русском языке)
Есть в моем списке в комментарии ниже
UFO just landed and posted this here
Еще по поводу ТК https://www.youtube.com/watch?v=I8LbkfSSR58&list=PLbgaMIhjbmEnaH_LTkxLI7FMa2HsnawM_ и вот подборка по ФП https://github.com/xgrommx/awesome-functional-programming (welcome to PR)

По-моему приверженцам "функционального" программирования чего-то в жизни не хватает.
Вот объясните мне (простому приверженцу принципа "работа должна быть сделана качественно и в сроки") — какую ценность несёт, хотя бы и подразделение функций на унарные, бинарные, тернарные и т. д.?
Сколько не читаю про так называемое ФП (функциональное программирование), так и не могу понять, что же в нём особенного? Функции используются практически в любом языке, практически в любой архитектуре. Нафига вводить еще один жаргон? Время девать некуда?

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

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

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


И для получения от ФП профита уже сегодня, совершенно не нужно знать что такое функторы, монады, моноиды и другие термины из Теории Категорий. Не ужели вы не используете лямбда функции и хотя бы такие паттерны как map, reduce, filter ?


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


разложение на категории ради разложения и присвоение терминов ради присвоения

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


Вот и с ФП такая же картинка. Если рассматривать отдельные кирпичики из него, возникнет недопонимание: зачем это может быть нужно? Всё так сложно и без явных преимуществ. Но кирпичики комбинируются, соединяются в причудливые схемы. И вот тогда программист пожинает profit. А так как область эта очень большая и развивается десятилетиями, да ещё и сугубо математична (а математика никогда не была особенно простой), то и нечему удивляться, что всё как-то абстрактно и сложно.

Спасибо за ответ. Ваша точка зрения мне понятна.

Всё же останусь при своём. А именно: считаю чрезмерное использование терминов излишней тратой времени и ресурсов.
Безусловно, всем, представленным в статье, парадигмам должны быть обучены все, без исключения, программисты. Но не на уровне терминов, а на подсознательном уровне. Ровно так же, как и с языками, на которых мы общаемся.
Но не на уровне терминов, а на подсознательном уровне

Можно ли понять диффуры без подготовки в виде многих лет изучения алгебры? Думаю да. Но какой ценой.

Как же излагать свои мысли, не используя термины? Вот разговаривают Вася с Петей о функторе, но как он называется никто из них не знает. Тогда неизбежно Вася придумает свой термин — А, а Петя — Б. И вот как-то не очень у них разговор сложится то…

Запили эту фичу на вот той вот штуке… ну, ты понял, которая принимает один тип, трансформирует данные и возвращает другой тип… Ну мы такое делали уже в проекте X.


@greendimka


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

Вот для этого, например.

Прошу заранее прощения за грубость и контрастность того, что будет ниже.

То есть разложение на категории ради разложения и присвоение терминов ради присвоения

Это зависит от точки зрения.

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

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

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

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


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

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

P.S. Исправил разметку, но суть текста не менял.
Спасибо за хороший развёрнутый ответ.

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

Просто вы, в конфронтационной манере типировав, задели тех, для кого эта статья предназначалась. Реакция читателей, думаю, очевидна. Минус поставить проще, чем потратить время на ответ :)
Вы абсолютно неправы, а greendimka задал очень важный вопрос: зачем все эти термины и как они помогают программировать?
Этот вопрос можно спокойно задавать в любой другой статье по любой парадигме. А ответ везде будет один — «кому-то так удобнее»
это глупый ответ людей, которые не смогли до конца разобраться в том, что для них придумали.

Человек, который разобрался, даст условия и покажет: как и когда этим пользоваться.

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

Термины программировать не помогают, а вот концепции, которые называются этими терминами — очень даже.


Возьмём функтор. Например, есть значение какого-то типа, обёрнутое в какой-то другой тип (Optional, List, Array… — во что угодно). И у вас уже есть функция fun1, которую можно применить к тому типу данных, который находится внутри обёртки (назовём этот тип Int). Но эту функцию нельзя применить к типу Int, который находится в обёртке (скажем, эта обёртка Optional). А вам это нужно. И вот вы пишете функцию fun1Optional. Можете вы её написать, не зная термина "функтор"? Какие проблемы — конечно можете!


Но тут у вас возникает задача сделать так, чтобы функция fun2, работающая со значениями типа Int, тоже могла работать со значениями Optional Int. И чтобы функция fun3 тоже так могла работать. И fun15. И вот вы пишете функции fun2Optional, fun3Optionalfun15Optional… Можете? Конечно, почему нет? Не зная ни о какой концепции, называемой термином "функтор".


Но если вы знаете о такой концепции, то вместо того, чтобы переписывать вручную кучу функций, работающих с типом Int, чтобы они работали с типом Optional Int, вы просто делаете обёрточный тип Optional функтором, определяя для него всего одну функцию map (или fmap — это одно и то же), которая принимает в качестве первого аргумента функцию, работающую с типом Int, в качестве второго аргумента — значение Optional Int, и применяет эту функцию Int -> ВоЧтоТоЕщё (которая уже имеется у вас!) к значению типа Int внутри обёрточного типа Optional. В результате вам не надо писать кучу функций fun1Optionalfun15Optional, а достаточно написать одну единственную функцию fmap для обёрточного типа Optional. И наличие у обёрточного типа Optional функции fmap делает его функтором.


Более того: наличие функции fmap позволяет вам использовать уже имеющиеся у вас функции не только со значениями типа Optional Int, но и с Optional Float, и с Optional String, и с Optional Bool — и т.д. Просто потому, что вы сделали обёрточный тип Optional функтором — путём определения для него всего одной функции.


Можно ли программировать без знания концепции функтора? Конечно можно! Просто у вас будет меньше code reuse, больше определений новых функций, а ваш код будет сложнее читаться, рефакториться и дебажиться. Помогает ли знание концепции "функтор" программировать? По-моему, да.

Ерунда! Обобщение можно придумать не зная концепции. Ведь кто-то придумал это первым, когда не было еще ни концепции, ни терминологии! Или теперь всем, кроме первого, отказать в уме?!
Концепции и терминологии упрощают, систематизируют и ускоряют процессы и структуры.

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

Думаю, речь об этом абзаце
Но тут у вас возникает задача сделать так, чтобы функция fun2, работающая со значениями типа Int, тоже могла работать со значениями Optional Int. И чтобы функция fun3 тоже так могла работать. И fun15. И вот вы пишете функции fun2Optional, fun3Optional… fun15Optional… Можете? Конечно, почему нет?

Это называется подтасовка, нет, я буду интуитивно использовать функтор, но не знать его определения. Мало того, использовать его или нет зависит от моих умственных способностей, а не от прочитанной книжки. Так что, в одиночку, формулировки не нужны. Вот для совместного программирования (> 1) помогают да, как и любые другие слова.

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


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

Вот представьте у вас программа не на 2 экрана, а на сотни тысяч строк кода или даже на 1 млн строчек кода (не важно как много), которую писали много лет разные команды, разные люди, разной квалификации в разном настроении и т. д. и т. п… И вот нам бы хотелось как-то иметь возможность научится понимать какими свойствами обладает данная конкретная программа (a reasoning about the code): какой тип результата и какие сайд эффекты мы получим при её выполнении на конкретный / произвольных входных данных? остановится ли она вообще или зависнет в бесконечном цикле? запустит ли она «ракеты» в конце концов :-)? существуют ли вообще такие входные параметры при которых результат будет некорректен / программа упадёт в рантайме? и т. д. Чтобы достичь этой цели мы можем нанять команду математиков и за N лет они проведут формальную верификацию. Но это слишком долго и дорого. А можно поступить разумнее: а пусть верификацией занимается компилятор, пусть он просто запрещает компиляцию логически некорректных программ! И вот ФП это первый шаг к этой цели, призванный дать программистам и компилятору минимальные строительные блоки для этого. Возможно в будущем их назовут не монойдами и монадами, а как-то ещё (см thenCombineAsync в Java8). Не лишним будет упомянуть зависимые типы, когда вы можете указать, например, что функция принимает не прочто Int или Long, а Nat (натуральное число), а значит у вас будет невозможно деление на 0 (аналогично и для выхода за границу диапазаона и т. п.). В общем, высокоуровнево идея очень проста: пишем программу используя некий набор «паттернов», которые позволяют компилятору «ризонить» о вашем коде и компилировать его только тогда, когда он может доказать корректность последнего. Кстати, такой подход помимо корректности, также способен дать автопарралелизацию кода компилятором за бесплатно (сайд эффекты то закодированы в системе типов, а значит компилятор 100% знает, что можно распараллелить и каким подходом, а что нет и т. д. и т. п.). На текущий момент в промышленных языках пока реализовано мало что из этого, но глобальная идея именно такая!
Давайте говорить реально: программа на 1 млн строк кода написана на С++, Java или C#. Практически без вариантов.
Ок. пусть будет 50 тыс строк кода. Просто большая программа… Не важно на самом деле 20 K, 50 K срок или 1 млн. Тут важна сама концепция (a reasoning about the code).
UFO just landed and posted this here
тут нет никаких вопросов.

Вопрос только в том, что программы на 1 млн строк кода существуют на С++, Java, C#, PHP, скорее всего Python. Остальные языки, при всей нашей радости от того же эрланга, к сожалению вызывают сомнение в этом (в существовании таких больших программ).

UFO just landed and posted this here
к слову сказать, окамль действительно вызывает удивление. На нём существует написанная в одно лицо реализация латеха, которая умела прямую генерацию PDF сильно до того, как этому научился сам латех (название очень неправильное: ant). Пары фич не хватало, но в целом это был восхитительный пример того, как эзотерическая штука реально помогает жить.

Правда, по причинам своей эзотеричности и замкнутости автора, оно вроде не пошло.

Но у окамля есть ряд очень важных практических свойств: компилируемость и мутабельный доступ к структурам.
UFO just landed and posted this here
UFO just landed and posted this here
а теперь можете пояснить свою интересную мысль без спец-терминов?
UFO just landed and posted this here
большое спасибо за попытку донести.

Позвольте, я попробую без спецтерминов.
Представьте себе функцию, выполняющую некоторые эффективные мутабельные вычисления. В общем случае, такая функция не будет чистой, что нехорошо. Однако мы можем ограничить всю мутабельность в этой функции некоторым локальным окружением, которое будет вынесено в её тип (примерно как в Rust в типы значений вносится область их жизни). А полиморфизм второго ранга позволит завернуть её в обёртку, которая, грубо говоря, создаёт необходимое окружение, прогоняет на нём вычисление и получает результат. И поскольку вне окружения гарантированно ничего не мутирует, итоговая обёртка будет чистой. В итоге получаем лучшее из двух миров – надёжная чисто-функциональная обёртка с эффективными императивными вычислениями внутри, которые при этом доказанно ничего не сломают.

Да, там правда еще будет нужно Data.STRef. Ну State просто хранит предидущее и оперирует этим как парой.
UFO just landed and posted this here
Неуважаемый, не стоит называть меня ннвеждой, пусть и чужими словами, коли не поняли суть вопроса.
Демонстрация парадигм ФП на котятах в Javascript-переложении, безусловно, хороша в пропагандистских и общеобразовательных целях, но, к сожалению, чревата импринтингом. Надо бы от этом в комментарию к переводу написать, т.к. монада, например, в общем случае, не есть контракт на chain/of в терминах реализации на Javacript.

Несмотря на это, перевод стоит добавить в избранное как intelligence mock.
Что такое «intelligence mock»?
«Интеллектуальный троллинг» или «умное издевательство», но, с оттенками карательной серьёзности.
Раз уже речь зашла о ФП на примере JavaScript, хочу обратить внимание общественности на один замечательный проект:
PureScript. Компилятор генерирует хороший человекочитаемый код.
Очень похож (практически клон) на Haskell, однако есть некоторые ключевые отличия.
Более глубоко можно ознакомиться в документе PureScript by Example.

Тогда можно еще и на Elm обратить внимание.

Тысячи их :) Но из всех них к терминам в статье ближе всего именно PureScript, т.к. он ближе всего к Haskell. Конечно, есть еще ghcjs, но это не особо прагматичный подход и тянет за собой большой рантайм (в первую очередь из-за сохранения семантики Haskell, а именно laziness). У PureScript вообще нет рантайма, его очень легко начать использовать в проекте (например, с webpack loader'ом) и сразу получить все плюсы чисто-функционального языка, не отказываясь при этом от богатой экосистемы Node.js (потому что у PureScript супер простой FFI). Что касается Elm, то это скорее «all-or-nothing» решение. Если захочется использовать third-party js библиотеки, то надо быть готовым к тому, чтобы городить огород кода (как js, так и elm). А еще, в отличие от PureScript, который уже достаточно стабилен (он все-таки копирует Haskell), Elm все еще развивается и буквально в недавнем релизе снова поменялся API. В общем, я считаю, что для продакшена он пока не готов, хотя идея довольно интересная. P.S.: Сам уже устал от js, «undefined is not a function», тонны рантайм ошибок, boilerplate'а из Immutable.js и пр., поэтому потратил довольно много времени на выбор альтернативы и остался с PureScript, т.к. это наиболее прагматичный из всех подход.
Смотрю многие хвалят функциональное программирование, посоветуйте как его можно приментить для инициализации UEFI. Подойдет любой вариант хоть для x86-64, хоть для ARM.
«Смотрю, многие хвалят метапрограммирование, паттерны проектирования, контейнеризацию, сервисно-ориентированную архитектуру, посоветуйте, как их можно применить для инициализации UEFI. Подойдёт любой вариант хоть для amd64, хоть для ARM.»

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

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


Есть такая штука — SSIS. По жизни штуковина довольно сложная, и вызывающая множество проблем и боли у разработчиков, которые её пытаются использовать для каких-то прикладных задач (а она действительно бывает нужна, просто поверьте пока что на слово). Итак, разработчики плачут, колются, но продолжают пожирать кактус с полуимперативными действиями по деплойменту и настройке SSIS-пакетов, воюют с разными версиями IDE, серверов и прочей дребеденью.


И тут появляется Chimayo. С использованием сравнительно небольшого количества паттернов функционального языка она позволяет описывать эти SSIS-задачи, формировать их в функциональном стиле, манипулировать как значениями первого класса, ну и всё такое. В общем, позволяет избавиться от боли и начать программистам, наконец, программировать.


К чему я это сказал? Я думаю, что для вашей инициализации UEFI просто не написан (или пока что вам не встретился) подходящий декларативный инструмент, использующий современные достижения функционального программирования. Если б он был — поверьте, вам бы понравилось, как и нам понравилось работать с Chimayo после ада ручной настройки SSIS.

http://stackoverflow.com/a/6638207
Если не ошибаюсь, OpenFirmware в старых Маках и сантехнике использовало Лисп для загрузчика. Потенциальная выгода в том, что скрипт на Лиспе может быть автоматически верифицирован малой кровью (то есть можно, вместо порочной идеи распространения подписей неограниченному кругу китайцев с паяльниками, реально проверять загрузчик на допустимость выполняемых им операций).
«Глупо и сварщику о таком спрашивать. „

Ну вот опять рабочий класс послали, а так хотелось приобщиться к прекрасному! Не “стрелять себе а ногу», манипулировать обьектами и функциональностью, наслаждаться шаблонами и паттернами.

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

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

UFO just landed and posted this here
ФП хороши для преобразования данных. Собственно, функции в математическом смысле только и делают что отображают элементы одних множеств на элементы других множеств. Идеальная программа на ФП не содержит сайд-эффектов.

Напротив, вся работа железа на низком уровне построена именно на сайд-эффектах. Настолько, что это даже сносит крышу даже обычным С-компиляторам. Например как вам такое — вы пишете в область памяти одно число, а потом читаете оттуда другое? Или читаете два раза подряд из одной и тоже ячейки памяти и при этом получаете совершенно разные значения?
Это не глюк, так работает вся memory-mapped периферия. Приходится использовать хитрые конструкции чтобы сишные компиляторы не ломали работу с периферией своими оптимизациями. Более того, нынешние процессоры тоже шибко умные и выбрасывают лишние (по их мнениею) обращения к памяти. А что тогда говорить про языки более высокого уровня? Поэтому и нет применеия ФП в UEFI.

Зато, если мне надо будет превращать тысячи HTTP запросов в тысячи HTTP ответов — я вользу Эрланг. Потому что ключевое слово — «превращать». Отображать множество HTTP запросов на множество HTTP ответов.
Мне кажется, что то, как сейчас построена работа железа на низком уровне вовсе не означает, что применения ФП там нет и быть не может. Просто так сложилось — мы сделали императивное железо и начали писать императивный код. Но если применить принципы ФП в нужном месте, то можно получить большой плюс, даже в отношении железа. Я считаю, что яркий пример — шейдеры. Раньше компьютерная графика была довольно слабой, но распараллелив вычисления удалось достигнуть большого прироста производительности. А распараллелить удалось применив принципы ФП. Ведь шейдеры, по сути — функции без сайд-эффектов: мы передаем данные в вершинный шейдер, а результат вычисления в фрагментный шейдер. Так что, с «инерцией мышления» я очень согласен.
UFO just landed and posted this here
Да, шейдеры — отличный пример. Но опять же это пример вычислений. Отображение множеств геометрии и текстур в множество пикселей конечной сцены.

С другой стороны есть куча задач, где вычисления как таковые не нужны. А нужно просто в нужное время выставлять нужные биты в нужных местах. И ещё — быстро реагировать на изменения битов в других местах. Это приблизительно то, чем занимается приснопамятный UEFI.

Хотя, если подняться чуточку выше — появляются и задачи для ФП. Мне тут подумалось, что можно например реализовать USB стек на ФП языках. Да и вообще задачи современного прошивкописания всё больше тяготеют к массовой параллельной обработке данных.
Netflix полностью построили свой бизнес на RxJava и RxJS что используется у них в проде. От части в Rx есть некие элементы FP

Пример Clojure показывает что наличием должной инфраструктуры, популяризации должной не добиться. Там через interop в java, доступны все богатства и мощь JVM мира. Но как видим, только небольшая прослойка ценителей ФП осторожно работают с ним или со Scala. Так что инерция мышления, самый главный враг ФП.

Но как видим, только небольшая прослойка ценителей ФП осторожно работают с ним или со Scala.
Мне кажется, что тут дело в том, что большинство ценителей ФП на дух не переносят Java, включая JVM.
Это на самом деле странная была затея создать функциональный язык поверх императивной виртуальной машины, которая даже оптимизацию хвостовой рекурсии не поддерживает. Мало нам что-ли императивной процессорной архитектуры?

Просто нужно понимать, что без популярной платформы (JVM, JS) популярность clojure была бы в разы меньше. Как и затраты на реализацию языка. Авторам clojure "всего-лишь" пришлось имплементировать компилятор и стандартную библиотеку, все самое сложное взяла на себя JVM.

С одной стороны — да, а с другой, разве не логичнее было бы компилировать не в java-байт-код, а, к примеру, в Common Lisp?
UFO just landed and posted this here
к слову сказать: в задаче конвертации (очень не люблю этот термин, поэтому заменю его транскодированием) видеопотоков к сожалению по большому счету очень мало места параллелизму (в стиле: 1000 медленных ядер). Нужен голый, беспощадный CPU с его хитростями типа SIMD.
UFO just landed and posted this here
есть такая долгая история про VLIW процессоры. Лет 20 минимум длится эта канитель со словами: мы сделали самый быстрый процессор, теперь надо только сделать к нему хороший компилятор, а вот компилятор как раз не получается сделать.

В итоге самый быстрый как вчера, так и сегодня это интел, а всякие VLIW-ы остались на откуп спец-задачам и академикам.
А потому что для каждой задачи свой инструмент. Я вот тоже по работе занимаюсь тем, что битики флипаю. Но когда мне надо обработать мегабайт трейс-логов я достаю Питон, а не начинаю писать парсер на С. Угадайте, почему?
В школе нас учат арифметики, операции над числами что есть некое множество которое поддается законам моноида. Но если обобщить все это и перенести на различный уровень абстракций то это правило будет справедливо и для других абстракций. Вот в программировании ТК это есть некая категория типов, а морфизмы это ф-ции вида a->b. Также эти ф-ции являются моноидами ибо есть единичный элемент id = x->x и бинарный оператор композиция. Функтор это тоже морфизм просто между 2-категориями (грубо говоря если вы простой тип упакуете в другой, например int в array). Задача ТК научится манипулировать между абстракциями не взирая на содержимое. Если был массив то после морфизма это и должен быть массив. Не важно был это массив целых, а стал массив строк, но ведь условие сохранения внешней структуры осталось это все тот же массив. В древнем Египте все начиналось с того, что люди рисовали 10,20,300 различных объектов (людей, и прочее). Но вскоре они поняли, что всему этому можно придать некую абстрактность и что 2 человека + 1 человек будет 3 и это справедливо к пирамидам, золоту и тд. Далее понимается тот факт что помимо простой манипуляции это все можно объединить в некий класс (множество) и иметь все те же законы (вот например в школе мы учили всякие коммутативные, ассоциативные, дистрибутивные, левая/правая тождественность и прочее) И в чем парадокс, что все эти законы ложаться на любой уровень абстракции. Вот например для моноида работают законы ассоциативности, левой и правой тождественности ну иногда (например как с числами, а более того у них два бинарных оператора типа +/* и два возможных множества, это множество целых и натуральных чисел) закон коммутативности. Об этом можно продолжать еще долго, просто нужно понять одно те, маленькие кирпичики что мы знали раньше при определенных условиях мы можем применять на различных структурах, если поддать их неким общим математическим правилам и законам. И тогда (в отличии от императивных подходов) мы можем строго уверять, что поведение будет строгим и закономерным. Думаю все рассказать в одном комментарии трудно =)
const map = (fn) => (list) => list.map(fn)
const add = (a) => (b) => a + b

Совершенно непонятная запись. Что здесь вообще написано?
еще для одного аргумента скобки можно опустить и будет все читаемей)

const S = x => y => z => x(z)(y(z))
const K = x => y => x
const I = S(K)(K)
Вот что мне не нравится в ООП, так то, что там методы объектов имеют побочные эффекты (влияют на члены объекта).

Ну и вообще не люблю трехэтажные абстракции.

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

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

Плюс это всё таки статья для тех, кто уже знает хаскель, а для них она мягко говоря бессмысленна, они уже итак всю терминологию знают.

Хотите сделать статью не для любителей хаскеля — используйте ну хотя бы яваскрипт что ли, но ни в коем случае не хаскелевский синтаксис.
> используйте ну хотя бы яваскрипт что ли

В статье все примеры на javascript.
const liftA2 = (f) => (a, b) => a.map(f).ap(b)


Да, конечно
Это действительно JavaScript. Правда, в примере ошибка, но не в синтаксисе.
https://habrahabr.ru/company/plarium/blog/270353/
И правда, так же намного нагляднее
var liftA2 = function(f){
    return function(a, b){
        return a.map(f).map(function(a){
             return a(b);
        })
    }
}
liftA2 = "haha";
var result = typeof(liftA2) === "string" ? liftA2 : liftA2([1,2],[3,4]);
Да, так сильно нагляднее для тех, кто привык к меньше экстраваганщине.

Только у вас внутри a перекрывается, что делает код не очень наглядным.

А зачем вторая часть текста с заменой функции на строку я не понял.

И плюс опять возвращаемся назад: зачем этот вычурный кусок кода? что он делает и сколько сотен строк более простого кода он экономит?
Вторая часть демонстрирует целесообразность введения const, как следствие решения двух проблем:
1. Оптимизация компилятора. Вместо этой переменной всегда можно подставить ее значение, что на больших объемах дает существенный выигрыш.
2. Утиная типизация иногда удобна, иногда крайне опасна, к тому же требует вот таких проверок. const решает вопрос указанием типа при первоначальном и единственном присвоении значения.

Это экстраваганщина, потому что вы первый раз увидели стрелочку или обожаете return? Завтра привыкнете, не переживайте. Ведь к `map`, который появился совсем недавно, вы претензий не предъявляете и не пробегаете массив циклом.

Конкретно этот кусок делает функцию liftA2 независимой от функции f, которую мы передаем. Это дает возможность использовать ее многократно с разными функциями, облегчает тестирование в разы, а значит и ускоряет написание кода. Хотя, подозреваю, до TDD вы еще тоже не добрались. Тогда, предупреждая вопрос, скажу. TDD нужно не для тестирования и даже не для описания требований, это приятный побочный эффект, но достигается и другими вещами. TDD предполагает разбиение кода на мельчайшие детали, проработку каждой из них в отдельности и доказательство поставленных функций. Чаще всего, программа не запускается целиком вообще до описания всех unit'ов. Зато внесение изменений всегда предсказуемо и однозначно. Если код поменяли в этом unit'е, то раз его тест не проходит, его и чинить (все зависимости его замоканы).
Так вот, функциональное программирование в разы облегчает создание таких кусочков, чистых функций. Нужные зависимости передаются, как параметры или каррируются и т.д.
В статье продемонстрированы инструменты такого подхода, на примере JavaScript.
Расскажите пожалуйста про свой опыт использования ФП на работе. Какого размера проекты вы поддерживали и в течении скольких лет?
Я могу рассказать про ваш опыт использования ФП на работе. Вы используете ФП и TDD всегда и везде, просто не зная терминологии, не используя современные инструменты и избегая вникания в суть, делаете это чуть менее эффективно.
Например, запуская программу целиком в командной строке или в браузере после каждого изменения и любуясь на ее работу.
Или доказывать то, что сам JS намного более функциональный язык, чем императивный и не надо, с этим никто не спорит.
А может быть вы использовали Angular с его декларативными шаблонами и DI? Или React с pure-компонентами? Нет? Ну lambda-функции и функции первого порядка в чистом виде ничем не хуже.
Вот в QBasic с этим были сложности, конечно.
Размер же проекта и необходимость его поддержки годами тоже определяется качественным кодом, иногда достаточно зайти на github раз в год и обновить dependencies у библиотек. А полезного, бизнес-кода настолько мало, насколько это возможно и его поддержка легка.
А иногда целыми днями сидишь и пилишь монолит на Swing, Laravel, Rails, когда регрессионные тесты вручную — основный вид деятельности.
Спасибо, но я обойдусь без вашего рассказа про то, как мы используем ФП.

Мы зарабатываем деньги, программируя на Эрланге в то время, как вы занимаетесь неизвестно чем и мне достаточно неприятно, когда какой-то аноним считает возможным меня поучать.
UFO just landed and posted this here
Каррирование — преобразование сигнатуры функции, для получения результата нужно передать то же количество аргументов. После каррирования получается функция, которая принимает часть аргументов и возвращает новую функцию, которая принимает другую часть аргументов и возвращает…

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

Каррирование и частичное применение связаны непосредственно друг с другом, поэтому это нормально, что не видно сначала разницы.
насколько понял из статьи, каррированная функция всегда принимает строго один аргумент и возвращает либо результат, либо функцию для следующего аргумента, а частично примененная функция просто принимает меньшее число аргументов чем изначальная функция и сразу возвращает результат.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here

Каррирование – способ представить функцию многих переменных в виде набора унарных. Частичное применение – способ получить функцию N переменных из функции N+K переменных, «зафиксировав» значения этих K. Они связаны только в том плане, что каррированные функции очень легко частично применять (передали только один аргумент – вуаля, у нас новая функция); но это вовсе не обязательное требование – см. C++-ный std::bind, например.

Тихий ужас. Я мало что понял из определений. Я подавлен. Удручён. У меня слов нет.

Я ещё никогда не чувствовал себя настолько дезориентированным.
Как я пользовался JS все эти годы без этих определений?

Или вопрос по-другому: зачем вы напомнили мне опять про ВУЗ и академические знания? :)
С функциональщиками лучше не спорить :)
Да ладно, что уж тут поделать.
это не функциональщики, а теоретики. Постят черти что в интернете, а потом идут на работу и пишут на своей яве.
UFO just landed and posted this here

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

всё, к черту, сюда налетели оголтелые теоретики. От таких для ФП главный вред.
Higher Order Function — функция высшего(а не высокого) порядка.

Свобода – это рабство!

Sign up to leave a comment.

Articles