Отключение, которое вы видите, не относится к FP и OOP. В основном это касается неизменяемости и математических формализмов против изменчивости и неформальных подходов.
Во-первых, давайте обойдемся с проблемой изменчивости: вы можете иметь FP с изменчивостью и ООП с неизменностью просто отлично. Еще более функциональный, чем-Haskell позволяет вам играть с изменяемыми данными, все, что вам нужно, вам просто нужно быть явным о том, что является изменяемым, и о порядке, в котором все происходит; и в стороне от эффективности, почти любой изменяемый объект может создавать и возвращать новый «обновленный» экземпляр вместо изменения собственного внутреннего состояния.
Большая проблема здесь - математические формализмы, в частности, тяжелое использование алгебраических типов данных в языке, немного удаленном от лямбда-исчисления. Вы отметили это с помощью Haskell и F #, но понимаете, что это только половина функционального программирования. семья Lisp имеет совсем другой, гораздо более свободный характер по сравнению с языками ML-стиля. Большинство систем ОО, широко используемых сегодня, носят весьма неформальный характер - формализмы существуют для ОО, но они не вызывают явно, как формалисты FP находятся в языках ML-стиля.
Многие из кажущихся конфликтов просто исчезают, если вы устраняете несоответствие формализма. Хотите создать гибкую, динамичную, ad-hoc систему OO поверх Lisp? Давай, все будет хорошо. Хотите добавить формализованную, неизменную систему OO на язык ML-стиля? Нет проблем, просто не ожидайте, что он будет хорошо играть с .NET или Java.
Теперь, вы можете быть интересно, что является соответствующий формализм для объектно-ориентированного программирования? Ну, вот линия удара: Во многом это более функционально, чем ML-стиль FP! Я вернусь к one of my favorite papers за то, что, по-видимому, является ключевым отличием: структурированные данные, такие как алгебраические типы данных в языках стиля ML, обеспечивают конкретное представление данных и возможность определять на нем операции; объекты обеспечивают абстракцию черного ящика над поведением и возможностью легкой замены компонентов.
Здесь есть двойственность, которая идет глубже, чем просто FP против OOP: она тесно связана с тем, что некоторые теоретики языка программирования называют the Expression Problem: с конкретными данными вы можете легко добавлять новые операции, которые с ней работают, но изменяя структуру данных сложнее. С объектами вы можете легко добавлять новые данные (например, новые подклассы), но добавлять новые операции сложно (подумайте о добавлении нового абстрактного метода в базовый класс со многими потомками).
Причина, по которой я говорю, что ООП является более функционально-ориентированным, состоит в том, что сами функции представляют собой форму поведенческой абстракции. Фактически, вы можете моделировать структуру OO-стиля в чем-то вроде Haskell, используя записи, содержащие кучу функций как объекты, позволяя типу записи быть «интерфейсом» или «абстрактным базовым классом», и иметь функции, которые создают записи, заменяют класса. Поэтому в этом смысле языки OO используют функции более высокого порядка далеко, гораздо чаще, чем, скажем, Haskell.
Для примера такого типа дизайна, который действительно используется для использования в Haskell, прочитайте источник для the graphics-drawingcombinators package, в частности, как он использует непрозрачный тип записи, содержащий функции, и объединяет вещи только с точки зрения их поведение.
EDIT: Несколько заключительных вещей, которые я забыл упомянуть выше.
Если OO действительно широко использует функции более высокого порядка, сначала может показаться, что он должен очень естественно входить в функциональный язык, такой как Haskell. К сожалению, это не совсем так. Это правда, что объектов, как я их описал (см. Документ, упомянутый в ссылке LtU), подходит только отлично. на самом деле результат - более чистый стиль OO, чем большинство языков OO, потому что «частные члены» представлены значениями, скрытыми закрытием, используемым для построения «объекта», и недоступны для чего-либо другого, кроме самого конкретного экземпляра. Вы не получаете гораздо более частного, чем это!
Что не очень хорошо работает в Haskell, является подтипирование. И, хотя я считаю, что наследование и подтипирование слишком часто используются неправильно на языках OO, некоторая форма подтипирования весьма полезна для возможности комбинировать объекты гибкими способами. Haskell не имеет неотъемлемого понятия подтипирования, и ручные замены обычно имеют чрезвычайно сложную работу.
В качестве альтернативы, большинство языков OO со статическими типами также делают полный хэш подтипов, слишком слабый с заменяемостью и не обеспечивает надлежащую поддержку для дисперсии сигнатур методов. На самом деле, я думаю, что единственный полномасштабный язык OO, который не исчерпал его полностью, по крайней мере, я знаю, это Scala (F #, похоже, слишком много уступок .NET, хотя, по крайней мере, я не думаю он делает ошибки ). У меня ограниченный опыт работы с многими такими языками, поэтому я определенно ошибаюсь.
В примечании, характерном для Haskell, его «классы типов» часто выглядят заманчивыми для программистов OO, о которых я говорю: «Не ходите туда». Попытка реализовать ООП таким образом будет только заканчиваться слезами. Подумайте о типах классов в качестве замены перегруженных функций/операторов, а не ООП.
+1, отличный ответ! – missingfaktor
Спасибо за впечатляющий ответ (и ссылки). У меня, вероятно, последующие вопросы после того, как я прочитаю материал. –