2009-11-24 3 views
61

Когда вы не хотите использовать функциональное программирование? Что это не так хорошо?Ловушки/Недостатки функционального программирования

Я больше ищут недостатки парадигмы в целом, а не такие вещи, как «не широко используется» или «нет хорошего отладчика». Эти ответы могут быть правильными на данный момент, но они касаются того, что FP представляет собой новую концепцию (неизбежную проблему), а не какие-либо присущие ей качества.

Похожие:

+4

Сообщество wiki. –

+6

«Ловушки объектно-ориентированного программирования» - это не CW после 1800 просмотров. (не пытайтесь быть грубым, просто сравнивая вопросы. Может быть, оба должны быть CW.: D) –

+0

У этого есть субъективный тег, но ответы, которые я видел до сих пор, были довольно объективными. Я могу удалить субъективный тег. – Brian

ответ

23

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

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

+5

«непреложность/ссылочная прозрачность, что означает, что вам нужно будет отлаживать реже» ... и поскольку все построено из небольших независимых функций, вы можете просто протестировать их напрямую; если каждая функция есть (a) правильная небольшая функция или (b) правильная композиция из двух или более правильных небольших функций, то wham! ваша программа верна. –

2

Вот некоторые проблемы, я столкнулся:

  1. Большинство людей считают, что функциональное программирование трудно понять. Это означает, что вам, вероятно, будет сложнее написать функциональный код, и для кого-то еще будет труднее забрать его.
  2. Функциональные языки программирования обычно медленнее, чем язык, подобный c. С течением времени это становится менее проблемой (поскольку компьютеры становятся быстрее, а компиляторы становятся более умными)
  3. Не будучи столь распространенным, как их императивные коллеги, бывает сложно найти библиотеки и примеры для общих проблем программирования. (Например, его почти всегда легче найти что-то для Python, то это для Haskell)
  4. Существует недостаток инструментов, особенно для отладки. Его определенно не так просто, как открыть Visual Studio для C# или eclipse для Java.
+5

Есть ли у вас какие-либо цифры или ссылки на номер поддержки 2? Также для номера 4 F # будет полностью поддерживаемым языком первого класса в Visual Studio 2010 –

+8

Я думаю, что пули 2-4 не являются неотъемлемой частью функционального программирования, но больше артефактов истории/культуры и т. Д. (То есть, хотя они могут быть правдой, они не верны «из-за FP», я думаю.) – Brian

+3

Re 1: Я не думаю, что это правда. Excel - функциональный язык программирования, и я не заметил, что его сложнее понять, чем, скажем, C, BASIC, Pascal или Python. На самом деле, это, вероятно, наоборот. –

8

Помимо вопросов, скорости или принятие и решение более основной вопрос, я слышал, что это положить, что с функциональным программированием, это очень легко добавлять новые функции для существующих типов данных, но это «жесткий», чтобы добавить новые типы данных , Рассмотрим:

(. Написанная в SMLnj Кроме того, пожалуйста, извините за несколько надуманный пример.)

datatype Animal = Dog | Cat; 

fun happyNoise(Dog) = "pant pant" 
    | happyNoise(Cat) = "purrrr"; 

fun excitedNoise(Dog) = "bark!" 
    | excitedNoise(Cat) = "meow!"; 

Я могу очень быстро добавить следующее:

fun angryNoise(Dog) = "grrrrrr" 
    | angryNoise(Cat) = "hisssss"; 

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

datatype Animal = Dog | Cat | Chicken; 

fun happyNoise(Dog) = "pant pant" 
    | happyNoise(Cat) = "purrrr" 
    | happyNoise(Chicken) = "cluck cluck"; 

fun excitedNoise(Dog) = "bark!" 
    | excitedNoise(Cat) = "meow!" 
    | excitedNoise(Chicken) = "cock-a-doodle-doo!"; 

fun angryNoise(Dog) = "grrrrrr" 
    | angryNoise(Cat) = "hisssss" 
    | angryNoise(Chicken) = "squaaaawk!"; 

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

+9

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

+0

@ Чак, правда, справедливо. Идея, которую я пыталась понять, заключается в том, что в ООП, пока вам все еще нужно писать реализации ваших методов, все это делается внутри класса. Добавляя новый подкласс, вам не нужно изменять родных или родителей. Фактически, достойные IDE будут автоматически заполнять подкласс подкласса для вас, когда вы создадите его с помощью пустых методов для реализации. Но если вы добавите новый метод в суперкласс, он сломает все реализующие классы. Обратное верно для функционала. Точка хорошо взята. –

+10

Это было названо * Проблема выражения * не кем иным, как Филиппом Вадлером. –

25

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

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

(Спасибо Jared Апдайка для списка разница внушения.)

+8

Это подчеркивает интересную проблему с FP: эффективное программирование в FP требует, чтобы вы знали определенные трюки, особенно касающиеся лени. В вашем примере на самом деле легко сохранить рекурсивный хвост кода (используя строгую левую складку) и избегать того, чтобы на вас что-то взорвалось. Вы не создали список назад и отменили список возврата. Хитрость заключается в использовании списков различий: http://en.wikipedia.org/wiki/Difference_list. Многие из этих трюков не так-то просто разобраться по своему усмотрению. К счастью, сообщество Haskell очень дружелюбное (канал IRC, списки рассылки). –

+4

Спасибо, Джаред. Хорошая информация. Однако в защиту моего описания стандартная библиотека OCaml делает это так, как я сказал (ограниченная стеками «карта» и хвостовая рекурсивная «rev_map»). – Chuck

14

Филипп Wadler написал статью об этом (под названием Почему никто не использует Functional Programming Languages) и рассмотрены практические подводные камни останавливая людей от использования FP языков:

Обновление: inaccessib ль старая ссылка для тех, кто с ПАСОМ доступом:

+6

, пожалуйста, разместите соответствующий текст статей. : D –

+0

@CrazyJugglerDrummer: Я думаю, что вся статья об этом ;-) –

+1

Я знаю, но я бы скорее посмотрел на нее как-то, не загружая и не открывая ее. Это возможно? –

3

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

Я изучаю класс функций сгиба в течение трех дней. У Fold, похоже, очень простое приложение: взять список и уменьшить его до одного значения. Haskell реализует для этого foldl и foldr. Эти две функции имеют множество разных реализаций. Существует альтернативная реализация foldl, называемая foldl'. Кроме того, существует версия с немного отличающимся синтаксисом: foldr1 и foldl1 с разными начальными значениями. Из них соответствует реализация foldl1' для foldl1. Как будто все это не было безумием, функции, которые fold[lr].* требуют в качестве аргументов и используют внутри редукции, имеют две отдельные подписи, только один вариант работает в бесконечных списках (r), и только один из них выполняется в постоянной памяти (как я понимаю (L), потому что только он требует redex). Понимание того, почему foldr может работать с бесконечными списками, требует по крайней мере достойного понимания языков lazy-behavoir и мелких деталей, что не все функции будут вынуждать оценку второго аргумента. Графики онлайн для этих функций запутывают как ад для тех, кто никогда не видел их в колледже. Нет эквивалента perldoc. Я не могу найти ни одного описания того, что делает любая из функций в прелюдии Haskell. Прелюдия - это своего рода предустановленный дистрибутив, который поставляется с ядром. Мой лучший ресурс - это действительно тот парень, с которым я никогда не встречался (Кейл), который помогает мне за огромный счет в свое время.

О, и не нужно сводить список к скалярному типу не-списка, функция идентификации для списков может быть записана foldr (:) [] [1,2,3,4] (подчеркивается, что вы можете скопировать в список).

/me возвращается к чтению.

+2

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

40

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

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

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

    Обычно специалистам не сложно писать быстрые функциональные программы; и на самом деле некоторые из наиболее эффективных параллельных программ для 8- и 16-ядерных процессоров теперь написаны в Haskell.

  • Скорее всего, кто-то, кто начнет функционировать, откажется от реализации обещанного прироста производительности, чем кто-то начнет, скажем, Python или Visual Basic. Там просто не так много поддержки в виде книг и средств разработки.

  • С ними связано меньшее количество людей. Stackoverflow - хороший пример; относительно немногие программисты Haskell регулярно посещают сайт (хотя часть этого состоит в том, что программисты Haskell имеют свои собственные оживленные форумы, которые намного старше и лучше установлены, чем Stackoverflow).

    Также верно, что вы не можете легко разговаривать со своим соседом, потому что концепции функционального программирования сложнее учить и усваивать, чем объектно-ориентированные концепции языков, таких как Smalltalk, Ruby и C++. Кроме того, объектно-ориентированное сообщество потратило годы на разработку хороших объяснений того, что они делают, тогда как сообщество функционального программирования, похоже, считает, что их материал, очевидно, велик и не требует каких-либо специальных метафор или лексики для объяснения. (Они не правы. Я все еще жду первой большую книгу Functional Design Patterns.)

  • Известного недостатка ленивого функционального программирования (применяется к Haskell или Clean, но не ОДЫ или Scheme или Clojure), так это то, что очень непросто прогнозировать затраты времени и пространства на вычисления . 0: —, даже эксперты не могут этого сделать. Эта проблема имеет основополагающее значение для парадигмы и не уходит. Есть отличные инструменты для обнаружения времени и пространства поведения post facto, но для их эффективного использования вы уже должны быть экспертом.

+8

«Обычно специалистам не сложно писать быстрые функциональные программы, и на самом деле некоторые из наиболее эффективных параллельных программ на 8- и 16-ядерных процессорах теперь написаны в Haskell». Только для самых тривиальных проблем. См. Http://flyingfrogblog.blogspot.com/2010/06/regular-shape-polymorphic-parallel.html –

+5

@Jon: Это зависит полностью от точной природы проблемы и от того, какую локальность кеша вы получаете. Измерение (из которого сравнительный анализ является только одним типом) покажет, что лучше всего; pontificating на веб-странице не будет. –

+1

@Donal: вычисление * сложности кеша * вашего алгоритма в простой многоядерной модели также является сильным индикатором, который лучше всего, как я сказал на этой веб-странице. –

24

Я думаю, что дерьмо, окружающее функциональные языки, является самой большой проблемой в функциональном программировании.Когда я начал использовать функциональное программирование в гневе, для меня было большим препятствием понять, почему многие из высокоразвитых аргументов, выдвинутых сообществом Lisp (например, о макросах и гомо-синоническом синтаксисе), были неправильными. Сегодня я вижу, что многие люди обманываются сообществом Хаскелла в отношении параллельного программирования.

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

«В целом эксперты не имеют никаких трудностей писать быстро функциональные программы, а на самом деле некоторые из лучших -переходящие параллельные программы на 8- и 16-ядерные процессоры теперь написаны в Haskell ».

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

В частности, реальная проблема в многоядерном программировании использует преимущества кэшей CPU, чтобы убедиться, что ядра не являются голодными данными, проблема, которая никогда не рассматривалась в контексте Haskell. Группа Чарльза Лейзерсона в MIT отлично справилась с этой проблемой и решила эту проблему, используя собственный язык Cilk, который стал основой параллельного программирования в реальном мире для мультикодов как в Intel TBB, так и в Microsoft TPL в .NET 4. Существует превосходное описание того, как этот метод можно использовать для написания элегантного высокого уровня императивного кода, который компилируется для масштабируемого высокопроизводительного кода в бумаге 2008 года The cache complexity of multithreaded cache oblivious algorithms. Я объяснил это в my review некоторых из современных исследований Parallel Haskell.

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

EDIT: Texas Multicore Technologies have also recently found Haskell to be underwhelming in the context of multicore parallelism.

+5

Parallelism/= HPC –

+4

Texas Multicore рекламирует свои собственные технологии против хронической реализации matrixmult, написанной с использованием списков (списки, которые я вам рассказываю!). Быстрый google показывает код, который будет нарисован из набора тестов для параллельных реализаций haskell. Рассмотрение его как идиоматической или «быстрой» или «хорошей» реализации, в отличие от, возможно, неэффективного теста для самого компилятора, является ошибкой категории. – sclv

+1

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

0

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

  1. кажется сравнительно редко, что это практично, чтобы выбрать функциональную модель некоторой реальной проблемой над императивный. Когда проблемная область является обязательной, использование языка с этим признаком является естественным и разумным выбором (поскольку в целом рекомендуется минимизировать расстояние между спецификацией и реализацией как часть уменьшения количества тонких ошибок). Да, это может быть преодолено достаточно умным кодером, но если вам нужна Rock Star Coders для этой задачи, это потому, что это слишком тяжело.

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

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

+2

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

Смежные вопросы