Недостатки Чисто Функционального Программирования

От автора: перевод статьи «Функциональное программирование непопулярно, потому что оно странное» вызвало множество дискуссий.



В нескольких комментариях вполне справедливо отмечалось, что при обсуждении недостатков функционального программирования хорошо бы опираться на современные и развитые функциональные языки (в оригинальной статье примеры были в шаблонах C++) и что, например, Haskell широко используется в промышленности в течение последних пяти лет. В связи с этим хотелось бы обратить внимание на две очень содержательные статьи из другого блога (автора книги F# для ученых ):(я)" Недостатки чисто функционального программирования "и (ii)" Почему Haskell так мало используется в промышленности Перевод первого из них я хотел бы представить ниже.

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

Словари теперь являются стандартной коллекцией, которую каждый разработчик ожидает найти в своей стандартной библиотеке.

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

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

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

Для некоторых приложений это непомерно медленно.

Более того, большинство функциональных языков (OCaml, Haskell, Scala) не способны выразить быструю изменяемую общую хеш-таблицу, поскольку в них нет убийственной комбинации материализованный дженерики , типы значений и быстрое написать барьер для сборщика мусора.

ВНИМАНИЕ! Остерегайтесь людей, которые пытаются утверждать, что чисто функциональные словари Haskell работают быстро, сравнивая их с изменяемыми хэш-таблицами того же Haskell .

Правильный вывод из этого сравнения заключается в том, что изменяемые хеш-таблицы Haskell работают медленно.

2. Чисто функциональных слабых хеш-таблиц не существует. В императивном языке со сборкой мусора отношения между узлами и ребрами графа могут быть выражены с помощью слабые хэш-таблицы .

Сборщик мусора соберет для вас недоступные подграфы.

Поскольку чисто функциональных слабых хеш-таблиц не существует, на чисто функциональном языке придется писать собственную сборку мусора ( ок.

перевод Я так понимаю, в смысле удаления недоступных подграфов вручную).

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

3. Не существует чисто функциональных потокобезопасных коллекций.

По определению, неизменяемые коллекции не могут поддерживать изменяемость, в том числе поточно-ориентированную.

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

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

Сравнивать Алгоритм Прима в 12 строках Python И Алгоритм Прима на 20 строках Haskell .

И почему, собственно, Haskell использует в библиотеке алгоритм Prim? Вероятно, потому, что алгоритм Краскала основан на структуре данных».

система непересекающихся множеств " ( коллекция поиска объединения , также известная как структура данных Disjoint-set), и ее эффективная реализация в функциональных языках отсутствует. 5. Инерция традиционных императивных структур данных и алгоритмов огромна.

Помимо графовых алгоритмов, существует множество областей информатики, в которых на протяжении 65 лет научная литература почти полностью фокусировалась на императивных решениях.

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

Ведь всего пару лет назад мемоизация в Haskell была темой кандидатской диссертации.

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

выяснилось .

6. Как выяснилось, все существующие реализации функциональных языков — как чистые, так и нечистые — предназначены для выделения слишком большого количества памяти.

Примерно в 1960 году Маккарти изобрел Лисп.

Базовая структура данных представляла собой односвязный список.

Каждый элемент списка размещался в куче отдельно.

Все современные функциональные языки развились из этой идеи.

В 70-е годы Scheme использовал по существу ту же стратегию представления данных, что и Lisp. В 80-е годы в SML добавили немного распаковки за счёт включения в язык кортежей, размещаемых в куче в виде твёрдых блоков памяти.

В 90-е годы в OCaml добавили немного больше распаковки за счёт включения в язык распакованных массивов действительных чисел.

В Haskell добавлена возможность распаковывать определенные типы данных.

Но по сей день ни один функциональный язык не распаковывает кортежи по умолчанию ( ок.

перевод Видимо, автор почему-то выбрал такой способ выражения «кортежи, расположенные в стеке по умолчанию»).

Даже F#, основанный на .

Net, где можно создавать любые типы значений, по-прежнему использует коробочные кортежи .

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

Следовательно, они загружают свои сборщики мусора гораздо больше, чем необходимо.

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

Следует отметить, что объявление такого поведения «недостатком» может быть спорным.

Ксавье Лерой из сообщества OCaml считает, что представление данных в стиле Lisp в OCaml является преимуществом, поскольку оно является основой превосходной производительности OCaml в среде автоматизированного доказательства теорем.

Готовить (Кок).

Ксавье заявляет что «стратегия Окамла для символьных вычислений близка к оптимальной».

Функциональные языки часто оптимизируются для высокопроизводительных чисто функциональных коллекций за счет низкой производительности императивных коллекций.

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

7. Чисто функциональное программирование хорошо для параллелизма в теории, но не очень хорошо для производительности на практике, а высокая производительность на практике — единственная реальная цель параллелизма.

Сегодня есть две причины писать параллельные программы.

Первый — писать объективно быстрые решения.

Во-вторых, принимать медленные решения не так уж и медленно.

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

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

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

Чисто функциональные языки, такие как Haskell, созданы для того, чтобы скрыть от программиста управление памятью и временем.



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

В Haskell это очень сложно.

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

По моему опыту, в таких языках, как C++, часто используется распараллеливание с использованием самых стандартных методов.

дает предсказуемый прирост в скорости, в отличие от Haskell , где производительность непредсказуема.

ВНИМАНИЕ! Остерегайтесь людей, которые говорят о масштабируемости программного обеспечения, не принимая во внимание абсолютную производительность.

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

Масштабируемость является необходимым, но недостаточным условием.

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

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

Я занимаюсь функциональным программированием более 20 лет. На протяжении десятилетий существовал социальный разрыв между программистами на функциональных языках и теми, кто решает реальные проблемы.



Слава Богу, эта проблема начала решаться по мере того, как для реальных задач стали использоваться функциональные языки вроде Scala, Clojure и F#; но в течение многих лет в сообществе функционального программирования доминировали высокомерные снобы, что очень затрудняло получение реальных решений реальных проблем.

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

Мне потребовалось много лет, чтобы понять, что не так в этих аргументах.

9. О функциональном программировании циркулирует много дезинформации.

Если вы критиковать производительность хеш-таблицы в Haskell (более поздняя критика Здесь ), то вы можете получить совершенно дикие советы от корифеев сообщества — например, они могут буквально советую вы просто отключите сбор мусора.

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

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

Мелисса О'Нил даже опубликовала научная статья , исправляющий решето Ратосфена на Хаскеле.

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



То же самое верно и для быстрой сортировки, где «элегантная» двухстрочная версия Haskell более чем в 1000 раз медленнее, чем версия C Седжвика, поскольку Haskell делает глубокую копию списков при каждом вызове быстрой сортировки, разрушая асимптотическую сложность оригинального алгоритма Хоара.

.

.

Смотрите также " Почему Haskell так мало используется в промышленности "где страница подробно опровергается" Хаскель в промышленности ".

От автора: Я также надеюсь когда-нибудь перевести статью «Почему Haskell так мало используется в индустрии», потому что она пытается опровергнуть мнение о том, что Haskell широко используется в индустрии последние пять лет. Но надо отметить, что (судя по комментариям к оригинальной версии на английском языке) все не так однозначно и сам автор, похоже, кое-где преувеличивает. Теги: #Функциональное программирование #программирование #языки программирования #программирование #haskell #Функциональное программирование

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2012-11-23 13:45:45
Баллов опыта: 469
Всего постов на сайте: 3
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.