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