Обновить
99
0.1
Роман Смирнов @Source

Head of Elixir at Ecom.tech

Отправить сообщение
1) Практические преимущества есть и без 100% чистоты… она не является самоцелью. Хотя может в Haskell и в Clean и является, я не в курсе, но в других функциональных языках с ней точно не носятся как с хрустальной вазой.
2) Необходимость использовать FFI на практике возникает крайне редко. И ничто не мешает скопировать аргументы и изменять in-place их копию, что вполне себе сэмулирует чистоту на уровне абстракции самой программы: «вызвали функцию, она вернула результат, никак не повлияв на свои аргументы». Все преимущества чистоты следуют сугубо из того, как это работает на верхнем уровне абстракции, а не из того, как это достигается на уровне ассемблера.
Везде свои компромиссы. Увеличение алгоритмической сложности некоторых алгоритмов не делает задачи не решаемыми, но показывает, что для таких алгоритмов есть более подходящие инструменты. Да и FFI никто не отменял, всегда можно дёрнуть реализацию алгоритма на C, если именно это является узким местом. Только задач, которые упираются в это, на практике встречается не так уж много. Ну а тем, у кого практический опыт другой и подобные задачи сплошь и рядом, лучше всё писать на С/С++.
Другими словами, абстрактный выбор между функциональными и императивными языками — это бессмысленный холивар. Язык надо выбирать исходя из своих конкретных задач.
Но это ничуть не меняет дело, и большинство проектов пишутся в императивно-оопшном стиле.
К чему эти обобщения на всю индустрию на основе своего личного опыта? На мой взгляд выбор между ФП и ООП — это совершенно бесполезное словоблудие (аля эта статья) вне контекста конкретной области программирования (а в идеале конкретного проекта). Ни то, ни другое не является лучшим выбором для 100% задач.

Вы разве не поняли, что я в верхнем посте именно это и имел в виду касательно quicksort?
Так а в чём смысл обсуждать quicksort в контексте ФП? То, что алгоритмы, основанные на in-place модификации данных, нельзя реализовать в рамках ФП, по-моему, вполне очевидно. Не понимаю, чем это Вас разочаровало…
Ахах, чего ж Вы так нервничаете, сами просили ООП в рамках ФП посмотреть, а как увидели, так сразу за лозунги уровня первого курса )))
Во-первых «наследование-инкапсуляция-полиморфизм» никогда не было определением ООП. Во-вторых, все бенефиты этой триады не зависят от объектно-ориентированности языка.
Наследование прекрасно заменяется композицией и примесями, что и в рамках классового ООП давно и активно применяется для борьбы с антипаттернами наследования. Инкапсуляция по факту только с иммутабельными данными возможна, пока Вы можете менять аргументы метода по ссылке, можно только притворяться, что есть инкапсуляция. Полиморфизм спокойно реализуется через duck-typing и typespecs (аля интерфейсы), в том числе и во многих ООЯП.
И да, Вы упорно путаете ФП и ФЯП. Поддержка ФП в какой-то мере уже включена почти во все популярные нефунциональные языки программирования. И с каждым годом всё больше языков расширяют эту поддержку… посмотрите хотя бы на C# и Java, на эти оплоты ООП, первый уже давно насквозь пронизан ФП, а второй окончательно признал популярность ФП 2 года назад.
P.S. Ну а на тему quicksort, это алгоритм на базе мутабельного массива. Имхо, совершенно очедичный факт, что он не может быть реализован в функциональном стиле вообще никак. Те эмуляции, которые Вы видели, никакого отношения к реализации quicksort не имеют.
не совсем «ортогональны», если «дополняют друг друга»?
Ну, вот была у Вас одна ось X и линейное мышление, а потом Вы добавили ортогональную ось Y, на которой тоже можно линейно мыслить. Но если Вы знаете про обе оси (дополнили одну другой), то у вас уже есть плоскость, а не линия. Так понятнее?
Чем больше парадигм Вы освоите, тем объёмнее станет мышление, а пытаясь кому-то доказать, что одной парадигмы достаточно для всего — Вы добровольно надеваете себе шоры.
А Вы сами то понимаете о чём спор?
Вы передёрнули факты «Мне кажется, ООП — более высокий уровень абстракции, и оно может существовать и с ФП «под капотом»», Вас протроллили в ответ зеркальным передёргиванием «Мне кажется, ФП — более высокий уровень абстракции, и оно может существовать и с ООП «под капотом»».
Теперь Вы скатились до истерики функции vs объекты, что совсем не то же самое, что ФП vs ООП, надеюсь, хоть это очевидный факт.
Ну а истина как всегда где-то посередине, ФП не конфликтует с ООП, они вообще ортогональны и взаимодополняют друг друга.
Зачем вспоминать акторы Scala, я не понял, это ведь частичная калька с Erlang. И да, ООП на базе акторов — это ООП в рамках ФП, которое Вы так жаждали увидеть.

в 99.99% случаев ООП — это-таки наследование-инкапсуляция-полиморфизм
ну, если Вам легче живётся с этой аффирмацией, то, пожалуйста, никто у Вас её не отнимает

По-моему Вы слегка путаете мутабельность данных с изменением состояния.
Мутабельность данных означает, что Вы можете полностью перезаписать значение переменной в ОЗУ и все переменные, указывающие на этот же адрес в памяти, также получат новое значение. Именно мутабельности данных нет в ФП, а состояние изменяется без проблем, просто оно не разделяемое, а по-настоящему инкапсулировано в лучших традициях ООП )))
Подумайте, знаете ли Вы хоть один императивный язык, поддерживающий инкапсуляцию в полной мере? Или метод одного объекта может вызвать метод другого объекта и передать ему часть своего состояния по ссылке? А ведь это прямое нарушение инкапсуляции, т.к. другой объект может спокойно и без каких-либо разрешений или уведомлений изменить значение по этой ссылке.

Отличается полной изоляцией и последовательной обработкой сообщений (методов в терминах ООП). Подробнее:


  1. Если в методе heat объекта Teapot произойдёт исключение, которое никто не перехватит, то упадёт вся программа. Если при обработке сообщения heat актора Teapot произойдёт исключение, то упадёт только он никак не затронув другие части программы. Причём стандартной практикой является наблюдение за акторами с помощью супервизора, который перезапустит актор Teapot в исходном состоянии и он снова сможет обрабатывать сообщения. За этим стоит целый подход к разработке ПО, под названием Let It Crash!
  2. Если два параллельных потока захотят сменить состояние объекта Teapot, то программа упадёт с race condition. Если два параллельных потока (процесса в терминах OTP) захотят сменить состояние актора Teapot, то эти смены будут применены последовательно, т.к. любое сообщение (вызов метода) попадает в очередь сообщений актора и он обрабатывает эту очередь по порядку.

Ну а в плане преимуществ, которые может дать ООП, ничем не отличается :-)

Но я все-таки надеюсь увидеть пример ООП под капотом ФП.
Наслаждайтесь и немного более подробно.
Я говорю — попробуйте решить задачу с ограничением времени в O(n). Можно даже амортизацию применять. Я находил функциональные алгоритмы с временной сложностью O(n*log(n)). Принципиально медленнее.
Извините, но не буду тратить на это время. За 10 лет практического опыта, мне эту задачу ни разу не приходилось решать для реального проекта. Поэтому лично мне вообще не интересно какая у неё алгоритмическая сложность.
Если Вы в каждодневной работе часто сталкиваетесь с подобными задачами и сложность функциональных алгоритмов Вас не устраивает, то возможно под Ваши задачи лучше подойдёт С++.
Ну а в чём проблема то? Берём Elixir или Erlang, пишем GenServer Teapot. У которого есть состояние(наличие и температура воды) и кто угодно может послать ему сообщение и узнать актуальное состояние в любой момент времени.
ООП вообще на акторах реализуется даже лучше, чем на классах. И мутабельность для этого не нужна.
В плане практических бизнес-задач у ФЯП проблем никаких нет.
Единственная проблема в ФП — реализовывать алгоритмы, построенные на базе мутабельности и массивов. Какие-то из них может даже не получиться реализовать за ту же сложность. Но, это довольно узкий класс задач… вспомните, когда Вы прошлый раз Кнута перечитывали?
Я про языки не писал… В функциональном подходе традиционно используется только хвостовая рекурсия, соответственно переполнение стека исключено.
Насчёт ограничений и языков… у всех по разному, у Erlang, например, глубина нехвостовой рекурсии ограничена только объёмом RAM.
переполнение стека из-за недооценки глубины рекурсии
ну вот, ещё одну проблему императивного подхода вспомнили, которая при функциональном подходе отсутствует )))

Программирование — это не математика, поэтому математически корректный алгоритм, который во что-то упёрся, с точки зрения программирования такой же ошибочный, как с NPE.
Функциональный язык — тот, в котором основная парадигма функциональная. Языков, в которых совсем невозможно ФП, по-моему, уже и нет, даже Java не устояла. С ООП то же самое, ООЯП — тот, в котором основная парадигма объектно-ориентированная. Но языков, в которых невозможно ООП, тоже практически нет.
Другими словами, вопрос только в качестве, удобстве и полноте поддержки той или иной парадигмы в языке.

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

Я уже несколько раз тут в комметах писал… не надо пытаться реализовывать императивные алгоритмы в функциональном стиле. Ничего хорошего из этого не получится. И это ни разу не аргумент против ФП.
Спрашивали про ФП, а не про языки… так что если уж по-честному, R, Wolfram Language и даже Python вполне активно используют ФП.
Я не улавливаю Вашей логики, честно говоря. В научных расчётах много чего используется, в том числе и ФП. Только какой от этого практический толк, если, допустим, Вы не занимаетесь научными расчётами?
Мне вот интереснее применение ФП для таких проектов как WhatsApp, Twitter и т.д.
Ok. Я просто когда-то давно тоже программировал на Delphi, но практически все, кого я знал, перешли на C# в районе 2007-2009 годов. Хотя, косвенно hh.ru это подтверждает, по тому же C# почти в 8 раз больше вакансий )
Вообще-то, конкурентность и параллелизм — это совсем разные понятия. Параллелизм тоже можно устроить на ФП, но я это не имел в виду в начальном сообщении.
Про программирование на GPU я Вам не подскажу, т.к. не интересуюсь этой темой. Если Вы хотели подколоть на тему, что для параллелизма есть инструменты получше, то вспомнили бы лучше Lambda- и Kappa-архитектуры. А то параллелизм числовых данных на GPU — это насколько узкая тема, что кроме учёных и любителей криптовалют, имхо, никому не интересна.
Так кривая ленивость — это тоже ошибка алгоритма, просто другого плана. Неведомой магии вообще в программировании не бывает, бывают неочевидные особенности )
Про Delphi — это тонкий троллинг или Вы до сих пор его в разработке используете?.. Честно говоря, ничего не знаю, про компонентно-ориентированное программирование или GUI на функциональных языках… Меня лично больше интересует область бэкенда для всяких веб- и mobile-приложений.
Скорость написания примерно такая же, как и на императивных языках, после того как осознаёшь функциональную парадигму и перестаёшь пытаться перетянуть туда императивные привычки.

И насколько углублённое знание лямбда-исчисления и прочей математики требуется чтобы писать быстро?
Просто не лезьте в Haskell и такие вещи как лямбда-исчисление, монады, функторы и т.д. Вас не потревожат )))
Т.е. ответ по существу — Вы можете вообще не знать что такое лямбда-исчисление и теория категорий, и прекрасно себя чувствовать на функциональных языках типа Elixir или Clojure, а также и на гибридных типа F#. Из ребусов только некоторые особенности записи могу вспомнить, но они скорее непривычные, чем сложные, и довольно легко осваиваются.

Информация

В рейтинге
4 095-й
Откуда
Россия
Зарегистрирован
Активность