Странные у Вас примеры, честно говоря. Почему Вы противопоставляете 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 миски) и всё прекрасно записывается при помощи отправки им сообщений.
Да, эта задача вертится вокруг состояний, но не надо думать, что функциональные языки не могут работать с состояниями. Просто они не используют для этого классы.
плохо подходят для прямого описания последовательных шагов.
Почему же, для описания последовательных шагов в виде цепочки функций ФП отлично подходит. Но хуже подходит для описания нескольких взаимовлияющих на разделяемое состояние последовательностей. Впрочем, до абсурда можно что угодно довести… давайте печь пирог при помощи ООП и классов Духовка, Противень, Миска, Мука, Сода, Соль, Масло, Сахар, Яйцо, Кефир, Банан, Орех, Полотенце.
Автор тупо хитрит, когда приводит рецепт из кулинарной книги в качестве императивной программы. Рецепт — это далеко ещё не программа.
Насколько я понимаю, в классической реализации View был больше похож на то, как это сделано в AngularJS. А возможность вызывать модель из View — это совсем о другом, и скорее это как раз нежелательная возможность.
Так я ж не говорю, что это всегда плохо, для базовых классов при желании можно найти плюсы. Но это не только в базовых классах, это в принципе по коду всего фреймворка встречается.
А человек был в неведении, что в любом Rails-приложении есть десятки классов, размазанных на несколько файлов.
По другому можно делать, но это грести против сообщества. Поэтому 'любовь к «размазыванию» классов на кучу файлов' — это факт, имеющий место в Ruby-сообществе. Поэтому странно видеть утверждения, что приложение, в котором это встречается, априори ненормальное.
По-моему наоборот, Ruby сейчас на пике моды… Появляются курсы типа «Врубиться в Ruby. Научим кодить с нуля». Люди далёкие от программирования начинают интересоваться как освоить Rails. В общем, настолько моден, что невольно вспоминается байка про банкира и чистильщика обуви.
Что Вы имеете в виду?
В самом приложении не должно быть Rails или гемов, расширяющих существующие классы?
Или если Вы выносите такие случаи в гемы — то это ok, а вот если в коде самого приложения — то это фу? Это ж двоемыслие какое-то...
Ни разу не видел чтобы в нормальном приложении класс "размазывался" на несколько файлов.
A Вы код самого Rails смотрели? Тот же ActiveRecord::Base — просто гигантский класс, размазанный на десятки файлов внутри самого фреймворка и ещё сотни файлов из сторонних гемов расширяют его же.
Да, реализация там была действительно неважная. Хотя говорят, что сейчас уже лучше.
Вы больше говорите о программистах, которые сразу начали с PHP, мой опыт не сильно репрезентативен, но я таких почти не встречал. Разве что видел их по вопросам на форумах.
Когда ООП добавили в PHP, это была уже знакомая для многих парадигма. Поэтому наверно и добавили.
Даже фреймворки типа CodeIgniter стали появляться. Хотя он тоже отличался весьма оригинальным видением ООП.
По поводу вопросов, специалистов по ООП в начале 00-х было на порядки больше, чем специалистов по ФП. Опять же благодаря моде, т.к. именно ООП преподавали во всех ВУЗах, а ФП касались на редких факультетах. Да и до сих пор ФП в виду непопулярности остаётся тем конкурентным преимуществом, про которое писал Пол Грэм. Инертность мышления ещё долго будет останавливать людей от изучения чего-то кроме ООП.
На тему массивы 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 миски) и всё прекрасно записывается при помощи отправки им сообщений.
Да, эта задача вертится вокруг состояний, но не надо думать, что функциональные языки не могут работать с состояниями. Просто они не используют для этого классы.
Автор тупо хитрит, когда приводит рецепт из кулинарной книги в качестве императивной программы. Рецепт — это далеко ещё не программа.
А человек был в неведении, что в любом Rails-приложении есть десятки классов, размазанных на несколько файлов.
По другому можно делать, но это грести против сообщества. Поэтому 'любовь к «размазыванию» классов на кучу файлов' — это факт, имеющий место в Ruby-сообществе. Поэтому странно видеть утверждения, что приложение, в котором это встречается, априори ненормальное.
Что Вы имеете в виду?
В самом приложении не должно быть Rails или гемов, расширяющих существующие классы?
Или если Вы выносите такие случаи в гемы — то это ok, а вот если в коде самого приложения — то это фу? Это ж двоемыслие какое-то...
A Вы код самого Rails смотрели? Тот же ActiveRecord::Base — просто гигантский класс, размазанный на десятки файлов внутри самого фреймворка и ещё сотни файлов из сторонних гемов расширяют его же.
Да, реализация там была действительно неважная. Хотя говорят, что сейчас уже лучше.
Вы больше говорите о программистах, которые сразу начали с PHP, мой опыт не сильно репрезентативен, но я таких почти не встречал. Разве что видел их по вопросам на форумах.
Когда ООП добавили в PHP, это была уже знакомая для многих парадигма. Поэтому наверно и добавили.
Даже фреймворки типа CodeIgniter стали появляться. Хотя он тоже отличался весьма оригинальным видением ООП.
По поводу вопросов, специалистов по ООП в начале 00-х было на порядки больше, чем специалистов по ФП. Опять же благодаря моде, т.к. именно ООП преподавали во всех ВУЗах, а ФП касались на редких факультетах. Да и до сих пор ФП в виду непопулярности остаётся тем конкурентным преимуществом, про которое писал Пол Грэм. Инертность мышления ещё долго будет останавливать людей от изучения чего-то кроме ООП.