Когда Вы можете передать функцию в качестве параметра другой функции, или вернуть функцию из функции — это, безусловно, часть ФП, так как только в этой парадигме существуют функции высшего порядка.
Отвечу вместо nehaev… Использование ФП на 100% оправдано, когда вам нужна высококонкурентная программа с высокой степенью надежности и отказоустойчивости.
В таком случае вы либо будете использовать готовый ФЯП, либо переизобретёте большую часть ФП на своём любимом ЯП, либо будете страдать на каждом углу от race conditions, dead locks, гейзенбагов и прочих весёлых вещей.
А вот в императивных языках — как написал, так и работает.
Вы уверены, что это в императивных языках, а не в Ваших фантазиях? )
Откуда ж берутся null pointer exception, GIL и ещё 100500 подводных камней, когда работает совсем не так, как написал… Проблемы везде есть, и в императивных языках их совсем не мало. Но можно найти проблемы и в Прологе и в Хаскеле, тут никто не спорит. А если пытаться на них в императивном стиле программировать, то вообще феерический ппц будет, о чём и статья.
Ok, мутабельный, так мутабельный… Но это не отменяет того факта, что Вы сравниваете 2 совершенно разных алгоритма и удивляетесь, получив вполне ожидаемый результат. Чтобы сравнение было уместным, возьмите LinkedList добавьте в него строки через AddLast, а потом превратите в строку с помощью Join (желательно найти тот, который без лямбд). Хоть StringBuilder работает не так, но это по крайней мере алгоритмы одной сложности.
Сейчас клиенты пишут либо под браузер, либо под мобильники. И там и там можно использовать ФП, но на, мой взгляд, оно как раз больше для высоконагруженного сервера подходит. На клиентах выигрыш от ФП как-то неочевиден.
По определению, массив — структура данных, оптимизированная для произвольного доступа по индексу. Список — структура данных, оптимизированная для последовательного перебора.
А с точки зрения логики, если бы реализация этих структур принципиально не отличалась, то достаточно было бы одного названия )
Я умею работать с массивами, даже знаю пару алгоритмов на базе массивов. Где тут в вашем ФП массивы? Как нет? А что есть? А, списки… в моём любимом языке класс массива называется ArrayList, значит список — это типа массив такой. Сейчас как напрограммирую… Ой, а почему всё так тормозит? Как это нельзя к списку по индексу обращаться, вот же я обращаюсь и всё работает, тупит правда, но это потому что ФП медленный.
Странные у Вас примеры, честно говоря. Почему Вы противопоставляете StringBuilder и неизменяемые строки? StringBuilder — это просто удобная обёртка для работы с теми самыми неизменяемыми строками. Внутри он скорее всего хранит список этих самых строк, а при необходимости объединяет их в один проход. Другими словами, по сути StringBuilder такой же иммутабельный, как список в любом ФЯП.
На тему массивы vs списки — это ж вообще на уровне К.О. Если не понимать разницу между этими структурами данных, то очень легко писать тормозной код — это факт. По сути все проблемы от того, что некоторые программисты пытаются в силу инертности мышления работать с неизменяемыми структурами данных так, как-будто они изменяемые. Но из этого ничего хорошего не получится и как-то глупо в этом ФП обвинять, оно в инертности мышления не виновато )))
P.S. К.О. просит передать: Нельзя на базе списков реализовывать алгоритмы, предусматривающие доступ к элементам по индексу.
Это да. Просто в реальных ситуациях программа выполняет кучу действий, какие-то быстрее в функциональном подходе, какие-то — в императивном, и в среднем разница не особо велика.
+ не все задачи требуют «максимально быстро», бывает просто «достаточно быстро»
Например, разбор заголовка MP3-файла можно сделать декларативно, но если это надо сделать для 100500 файлов, то придётся вспомнить про fseek. Другими словами, инструмент зависит от задачи, и чем больше у вас инструментов, тем легче выбрать наиболее подходящий под конкретную задачу.
Дело даже не в затруднении реализации привычных алгоритмов, а в том, что при добавлении элемента в список, мне нужно создать целый новый список. А если он большой?
На практике это очень легко решается — хвост списка всегда переиспользуется под капотом, он же неизменяемый. Т.е. когда вы добавляете элемент в начало списка — это равнозначно смене указателя на голову списка, никакого копирования данных не происходит.
пользователю разумно ожидать, что какое-то действие программы будет выполняться, скажем минут за 5, а с нашими алгоритмами, оно выполняется за 30?
Вы в каких-то стереотипах живёте… С чего Вы взяли, что ФП само по себе что-то делает в разы медленнее… для реальных задач скорее будет 5 и 6, и то при условии, что 5 — это что-то из серии C/C++, D, Go, Rust.
Более того существуют интерпретируемые императивные ЯП, которые как раз в разы медленнее, компилируемых (в том числе и функциональных). И ничего, прекрасно себе существуют и куча применений им находится.
Насколько реально, для прикладных задач, строго сформулировать разумные ожидания пользователя? Как это вообще сделать? Кто должен этим заниматься, и сколько времени это займет?
Вообще, есть такая профессия, бизнес-аналитик называется. Впрочем, Вы там в сторону математического доказательства корректности углубились. Хотя по факту это не имеет смысла, достаточно того, что ФП упрощает то самое юнит-тестирование.
Что о недостатках, что о достоинствах надо говорить с учётом области применения, иначе получается оторванный от реальности маркетинговый булшит. Desktop, Web, Mobile, Machine Learning, AI, разработка ОС и драйверов и т.д. — это всё принципиально разные области.
Функциональный подход хорош тем, что позволяет взглянуть на решаемые задачи под другим углом.
Естественно, если ваша основная задача выжать максимум производительности, то вы пишете на C, тут без вариантов. Если же вы применяете какие-то высокоуровневые ЯП, то совсем не исключено, что ФП-решение покажет лучшую производительность на ваших задачах.
P.S. Кстати, какой смысл говорить о чистых языках как-будто о ФП вцелом, если из известных чистых есть только Haskell?
Я расцениваю минусы к предыдущему комментарию как признание в неспособности написать программу по мотивам указанного в статье рецепта.
Если так сложно на императивном языке написать, то попробуйте перевести с функционального: пример
Это для конкурентного то выпекания? Ну да мьютекс на миску — это так похоже на реальный мир, не то, что сообщение от одного пекаря другому, что миска освободилась :-D
Запускается 4 актора (печь, противень и 2 миски) и всё прекрасно записывается при помощи отправки им сообщений.
Да, эта задача вертится вокруг состояний, но не надо думать, что функциональные языки не могут работать с состояниями. Просто они не используют для этого классы.
В таком случае вы либо будете использовать готовый ФЯП, либо переизобретёте большую часть ФП на своём любимом ЯП, либо будете страдать на каждом углу от race conditions, dead locks, гейзенбагов и прочих весёлых вещей.
Откуда ж берутся null pointer exception, GIL и ещё 100500 подводных камней, когда работает совсем не так, как написал… Проблемы везде есть, и в императивных языках их совсем не мало. Но можно найти проблемы и в Прологе и в Хаскеле, тут никто не спорит. А если пытаться на них в императивном стиле программировать, то вообще феерический ппц будет, о чём и статья.
А с точки зрения логики, если бы реализация этих структур принципиально не отличалась, то достаточно было бы одного названия )
На тему массивы vs списки — это ж вообще на уровне К.О. Если не понимать разницу между этими структурами данных, то очень легко писать тормозной код — это факт. По сути все проблемы от того, что некоторые программисты пытаются в силу инертности мышления работать с неизменяемыми структурами данных так, как-будто они изменяемые. Но из этого ничего хорошего не получится и как-то глупо в этом ФП обвинять, оно в инертности мышления не виновато )))
P.S. К.О. просит передать: Нельзя на базе списков реализовывать алгоритмы, предусматривающие доступ к элементам по индексу.
+ не все задачи требуют «максимально быстро», бывает просто «достаточно быстро»
Например, разбор заголовка MP3-файла можно сделать декларативно, но если это надо сделать для 100500 файлов, то придётся вспомнить про fseek. Другими словами, инструмент зависит от задачи, и чем больше у вас инструментов, тем легче выбрать наиболее подходящий под конкретную задачу.
«OOP means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things» © A.Kay
Поэтому практически значимые отличия ООП и ФП:
1) (Им-)мутабельность данных. В ФП данные неизменяемы, что затрудняет реализацию некоторых привычных алгоритмов, основанных на in-place модификации данных. Зато упрощает сборку мусора и конкурентный доступ.
2) Работа с разделяемым состоянием. ООП равномерно размазывает его по всей программе, попутно позорно нарушая инкапсуляцию при помощи геттеров и сеттеров. А ФП изолирует работу с разделяемым состоянием. И вместо блокировок использует очереди сообщений или STM.
Более того существуют интерпретируемые императивные ЯП, которые как раз в разы медленнее, компилируемых (в том числе и функциональных). И ничего, прекрасно себе существуют и куча применений им находится.
Вообще, есть такая профессия, бизнес-аналитик называется. Впрочем, Вы там в сторону математического доказательства корректности углубились. Хотя по факту это не имеет смысла, достаточно того, что ФП упрощает то самое юнит-тестирование.
Естественно, если ваша основная задача выжать максимум производительности, то вы пишете на C, тут без вариантов. Если же вы применяете какие-то высокоуровневые ЯП, то совсем не исключено, что ФП-решение покажет лучшую производительность на ваших задачах.
P.S. Кстати, какой смысл говорить о чистых языках как-будто о ФП вцелом, если из известных чистых есть только Haskell?
Если так сложно на императивном языке написать, то попробуйте перевести с функционального: пример
Вот, например, выпекание пирога на Elixir:
http://pastie.org/10879491
Запускается 4 актора (печь, противень и 2 миски) и всё прекрасно записывается при помощи отправки им сообщений.
Да, эта задача вертится вокруг состояний, но не надо думать, что функциональные языки не могут работать с состояниями. Просто они не используют для этого классы.