Изучив функциональное программирование на Haskell и F #, парадигма ООП кажется задом наперед с классами, интерфейсами, объектами. Какие аспекты ПС я могу использовать на работе, чтобы мои коллеги могли понять? Стоит ли говорить с моим боссом о каких-либо стилях FP о переподготовке моей команды, чтобы мы могли их использовать?
Возможные аспекты ФП:
- неизменность
- Частичное применение и карри
- Функции первого класса (указатели на функции / функциональные объекты / шаблон стратегии)
- Ленивая оценка (и монады)
- Чистые функции (без побочных эффектов)
- Выражения (в сравнении с утверждениями - каждая строка кода создает значение вместо или в дополнение к побочным эффектам)
- Рекурсия
- Сопоставление с образцом
Является ли это свободным для всех, где мы можем делать все, что поддерживает язык программирования, до тех пор, пока язык не поддерживает его? Или есть лучшее руководство?
object-oriented
programming-practices
functional-programming
paradigms
Трезубец Д'Гао
источник
источник
Ответы:
Функциональное программирование - это другая парадигма от объектно-ориентированного программирования (другое мышление и другое мышление о программах). Вы начали понимать, что здесь есть несколько способов (объектно-ориентированных) думать о проблемах и их решениях. Есть и другие (на ум приходят процедурное и общее программирование). То, как вы реагируете на эти новые знания, принимаете ли вы и интегрируете ли вы эти новые инструменты и подходы в свой набор навыков, будет определять, будете ли вы расти и станете более совершенным, опытным разработчиком.
Мы все обучены справляться и чувствуем себя комфортно с определенным уровнем сложности. Мне нравится называть это лимитом вознаграждения человека (от Watership Down, как высоко вы можете считать). Это отличная вещь, чтобы расширить свой кругозор, способность рассмотреть больше вариантов и иметь больше инструментов для подхода и решения проблем. Но это изменение, и оно вырывает вас из вашей зоны комфорта.
Одна из проблем, с которой вы можете столкнуться, заключается в том, что вы будете менее довольны следованием толпой «все является объектом». Возможно, вам придется проявить терпение, поскольку вы работаете с людьми, которые могут не понимать (или не хотят понимать), почему функциональный подход к разработке программного обеспечения хорошо работает для определенных проблем. Так же, как общий подход к программированию хорошо работает для определенных проблем.
Удачи!
источник
Функциональное программирование обеспечивает очень практичную и практичную производительность при повседневном написании кода: некоторые функции предпочитают краткость, что замечательно, потому что чем меньше кода вы пишете, тем меньше сбоев и меньше обслуживания.
Будучи математиком, я нахожу причудливые функциональные вещи очень привлекательными, но обычно они полезны при разработке приложения: эти структуры могут кодировать в структуре программы множество инвариантов программы, не представляя эти инварианты переменными.
Моя любимая комбинация может выглядеть довольно тривиально, однако я считаю, что она очень сильно влияет на производительность. Эта комбинация является частичным применением и функциями каррирования и первого класса, которые я бы никогда не написал снова для цикла for : вместо этого передайте тело цикла в функцию итерации или отображения. Меня недавно наняли на работу в C ++, и я забавно заметил, что я полностью утратил привычку писать циклы for!
Сочетание рекурсии и сопоставления с образцом устраняет необходимость в этом шаблоне проектирования посетителя . Просто сравните код, необходимый для программирования вычислителя булевых выражений: в любом функциональном языке программирования это должно быть около 15 строк кода, в ООП правильное решение - использовать этот шаблон проектирования Visitor , который превращает этот игрушечный пример в обширное эссе. Преимущества очевидны, и я не знаю ни одного неудобного.
источник
list.forEach(System.out::println);
С точки зрения FP,println
функция принимает два аргумента, цельPrintStream
и значение,Object
но методCollection
sforEach
ожидает функцию с одним аргументом только который может быть применен к каждому элементу. Таким образом, первый аргумент привязан к экземпляру, найденному приSystem.out
переходе к новой функции с одним аргументом. Это проще, чемBiConsumer<…> c=PrintStream::println; PrintStream a1=System.out; list.forEach(a2 -> c.accept(a1, a2));
Возможно, вам придется ограничить, какие части ваших знаний вы используете на работе, как Супермен должен притворяться Кларком Кентом, чтобы наслаждаться преимуществами нормальной жизни. Но знание большего никогда не повредит тебе. Тем не менее, некоторые аспекты функционального программирования подходят для объектно-ориентированного магазина, а о других аспектах может стоить поговорить с вашим боссом, чтобы вы могли повысить средний уровень знаний своего магазина и в результате написать более качественный код.
FP и OOP не являются взаимоисключающими. Посмотри на Скалу. Некоторые думают, что это худшее, потому что это нечистое FP, но некоторые думают, что это лучшее по той же причине.
Один за другим, вот некоторые аспекты, которые прекрасно работают с ООП:
Чистые функции (без побочных эффектов) - все языки программирования, которые я знаю, поддерживают это. Они значительно упрощают ваш код и позволяют использовать его по мере возможности. Вам не нужно называть это FP. Просто назовите это хорошей практикой кодирования.
Неизменность: String, возможно, является наиболее часто используемым объектом Java и является неизменным. Я рассказываю об неизменных объектах Java и неизменных коллекциях Java в своем блоге. Часть этого может быть применима к вам.
Функции первого класса (указатели на функции / функциональные объекты / шаблон стратегии). Начиная с версии 1.1 в Java существовала мутантная версия этого мутанта с большинством классов API (а их сотни), которые реализуют интерфейс Listener. Runnable, вероятно, наиболее часто используемый функциональный объект. Функции первого класса - это больше работы для написания кода на языке, который не поддерживает их изначально, но иногда стоит дополнительных усилий, когда они упрощают другие аспекты вашего кода.
Рекурсия полезна для обработки деревьев. В магазине ООП это, вероятно, основное подходящее использование рекурсии. Использование рекурсии для удовольствия в ООП, вероятно, следует осудить, если ни по какой другой причине, кроме большинства языков ООП, по умолчанию не предусмотрено пространство стека, чтобы сделать это хорошей идеей.
Выражения (в сравнении с утверждениями - каждая строка кода создает значение вместо побочных эффектов или в дополнение к ним) - Единственный оценочный оператор в C, C ++ и Java - это троичный оператор . Я обсуждаю подходящее использование в моем блоге. Вы можете написать несколько простых функций, которые можно использовать повторно и использовать для оценки.
Ленивая оценка (и монады) - в основном ограничивается отложенной инициализацией в ООП. Без языковых функций для его поддержки вы можете найти некоторые полезные API-интерфейсы, но написать свой собственный сложно. Вместо этого максимально увеличьте использование потоков - примеры интерфейсов см. В интерфейсах Writer и Reader.
Частичное применение и каррирование - не практично без функций первого класса.
Pattern Matching - вообще не рекомендуется в ООП.
Таким образом, я не думаю, что работа должна быть бесплатной для всех, где вы можете делать все, что поддерживает язык программирования, до тех пор, пока язык не поддерживает его. Я думаю, что читабельность ваших коллег должна быть вашим лакмусовым тестом для кода, созданного по найму. Где это вас раздражает больше всего, я бы хотел начать обучение на работе, чтобы расширить кругозор ваших коллег.
источник
public interface BiConsumer<T, U> { public void accept(T t, U u); }
в java.util.function есть и другие полезные функциональные интерфейсы.Most OOP languages don't have the stack space for it
В самом деле? Все, что вам нужно, это 30 уровней рекурсии для управления миллиардами узлов в сбалансированном двоичном дереве. Я уверен, что мое пространство стека подходит для гораздо большего количества уровней, чем этот.Помимо функционального программирования и объектно-ориентированного программирования, существует также декларативное программирование (SQL, XQuery). Изучение каждого стиля поможет вам получить новое понимание, и вы научитесь выбирать правильный инструмент для работы.
Но да, это может быть очень сложно писать код на языке, и знать, что если бы вы использовали что-то другое, вы могли бы быть более продуктивным для конкретной проблемной области. Тем не менее, даже если вы используете такой язык, как Java, можно применять концепции из FP к вашему Java-коду, хотя и окольными путями. Например, инфраструктура Guava делает это.
источник
Как программист, я думаю, что вы никогда не должны прекращать учиться. Тем не менее, очень интересно, что изучение FP портит ваши навыки ООП. Я склонен думать об обучении ООП как об обучении катанию на велосипеде; Вы никогда не забудете, как это сделать.
По мере того как я изучал все тонкости FP, я обнаружил, что думаю более математически и стал лучше понимать средства, с помощью которых я пишу программное обеспечение. Это мой личный опыт.
По мере того, как вы приобретаете больше опыта, основные концепции программирования будет гораздо труднее потерять. Поэтому я советую вам спокойно относиться к FP, пока концепции ООП полностью не закрепятся в вашем уме. FP - это определенный сдвиг парадигмы. Удачи!
источник
Уже есть много хороших ответов, поэтому мой ответит на часть вашего вопроса; а именно, я предпочитаю предположение вашего вопроса, поскольку ООП и функциональные возможности не являются взаимоисключающими.
Если вы используете C ++ 11, существует много таких функциональных функций программирования, встроенных в языковую / стандартную библиотеку, которые хорошо сочетаются с ООП. Конечно, я не уверен, насколько хорошо TMP будет принят вашим начальником или коллегами, но дело в том, что вы можете получить многие из этих функций в той или иной форме на нефункциональных языках / языках ООП, таких как C ++.
Использование шаблонов с рекурсией во время компиляции зависит от ваших первых 3 баллов,
Поскольку значения шаблона являются неизменяемыми (константы времени компиляции), любая итерация выполняется с использованием рекурсии, а ветвление выполняется с использованием (более или менее) сопоставления с образцом в форме разрешения перегрузки.
Что касается других пунктов, использование
std::bind
иstd::function
дает вам частичное применение функции, а указатели функций встроены в язык. Вызываемые объекты являются функциональными объектами (а также частичным применением функций). Обратите внимание, что под вызываемыми объектами я имею в виду те, которые определяют ихoperator ()
.Ленивая оценка и чистые функции были бы немного сложнее; для чистых функций вы можете использовать лямбда-функции, которые захватывают только по значению, но это не идеально.
Наконец, вот пример использования рекурсии во время компиляции с частичным применением функции. Это несколько надуманный пример, но он демонстрирует большинство пунктов выше. Он будет рекурсивно связывать значения в данном кортеже с данной функцией и генерировать (вызываемый) функциональный объект
источник