Поскольку машинный язык (например, 0110101000110101
) компьютерные языки, как правило, эволюционировали до более высоких форм абстракции, обычно облегчая понимание кода при его применении к проблеме. Ассемблер был абстракцией над машинным кодом, C был абстракцией над ассемблером и т. Д.
Кажется, что объектно-ориентированный дизайн очень хорошо позволяет нам моделировать проблему с точки зрения объектов, например, проблема системы регистрации университетских курсов может быть смоделирована с помощью Course
класса, Student
класса и т. Д. Затем, когда мы пишем решение в ОО-языке у нас есть схожие классы, которые получают обязанности, и это, как правило, полезно для проектирования, особенно для модульности кода. Если я передам эту проблему 10 независимым командам, которые решают ее методом ОО, обычно у 10 решений будут общие классы, относящиеся к проблеме. Когда вы начинаете связываться и взаимодействовать с этими классами, может быть много различий, поэтому не существует такого понятия, как «нулевой разрыв представления».
Мой опыт работы с функциональным программированием очень ограничен (нет реального использования, только программы типа Hello World). Я не вижу, как такие языки позволяют легко сопоставлять решения FP с проблемами (с небольшим разрывом представления), как это делают языки OO.
Я понимаю преимущества FP по сравнению с параллельным программированием. Но я что-то упускаю или FP не об уменьшении репрезентативного разрыва (облегчения понимания решений)?
Еще один способ задать вопрос: будет ли много общего у кода FP 10 различных команд, решающих одну и ту же реальную проблему?
Из Википедии по абстракции (информатика) (выделено мое):
Языки функционального программирования обычно демонстрируют абстракции, связанные с функциями , такие как лямбда-абстракции (превращение члена в функцию некоторой переменной), функции высшего порядка (параметры являются функциями), абстракция скобки (превращение члена в функцию переменной).
Пробел в представлении может быть потенциально увеличен, потому что [некоторые] реальные проблемы не легко моделируются с помощью таких абстракций.
Еще один способ уменьшить разрыв в представлении состоит в том, чтобы проследить элементы решения до проблемы. Буквы 0
's' и 's' 1
в машинном коде очень сложно отследить, тогда как Student
класс легко отследить. Не все ОО-классы легко отслеживаются в проблемном пространстве, но многие делают.
Разве абстракции FP всегда нуждаются в объяснении, чтобы выяснить, какую часть пространства задач они решают (кроме математических задач)?ОК - у меня все хорошо. Посмотрев еще много примеров, я вижу, как абстракции FP очень понятны для частей проблемы, которые выражаются в обработке данных.
Принятый ответ на связанный вопрос Можно ли использовать UML для моделирования функциональной программы? - говорит: «Функциональные программисты не очень часто используют диаграммы». Мне действительно все равно, если это UML, но это заставляет меня задуматься о том, чтобы абстракции FP были просты для понимания / общения, если нет широко используемых диаграмм (при условии, что этот ответ правильный). Опять же, мой уровень использования / понимания FP тривиален, поэтому я не понимаю необходимости диаграмм в простых программах FP.
У ОО-дизайна есть уровни абстракции на уровне функций / классов / пакетов с инкапсуляцией (контроль доступа, скрытие информации) на каждом, что облегчает управление сложностью. Это элементы, которые позволяют легче перейти от проблемы к решению и обратно.
Многие ответы говорят о том, как анализ и проектирование выполняются в FP способом, аналогичным ОО, но пока никто не цитирует ничего высокого уровня (Пол привел некоторые интересные вещи, но это низкий уровень). Я вчера много гуглял и нашел интересную дискуссию. Следующее - от Рефакторинга Функциональных Программ Саймона Томпсона (2004) (выделено мной)
При проектировании объектно-ориентированной системы считается само собой разумеющимся, что проектирование будет предшествовать программированию. Проекты будут написаны с использованием системы, подобной UML, которая поддерживается такими инструментами, как Eclipse. Начинающие программисты могут хорошо изучить подход визуального дизайна, используя такие системы, как BlueJ. Работа над подобной методологией для функционального программирования описана в FAD: Функциональный анализ и проектирование , но мало другой работы существует. Там может быть несколько причин для этого.
Существующие функциональные программы имеют масштаб, который не требует проектирования. Многие функциональные программы невелики, но другие, такие как компилятор Glasgow Haskell, являются существенными.
Функциональные программы напрямую моделируют область приложения, что делает дизайн неактуальным. Хотя функциональные языки предоставляют множество мощных абстракций, трудно утверждать, что они предоставляют все и только абстракции, необходимые для моделирования реального мира.
Функциональные программы построены как развивающаяся серия прототипов.
В вышеупомянутой диссертации на получение степени доктора философии преимущества использования анализа и методологии проектирования (ADM) изложены независимо от парадигм. Но выдвигается аргумент, что ADM должны соответствовать парадигме реализации. То есть OOADM лучше всего подходит для программирования OO и плохо применяется к другой парадигме, такой как FP. Вот отличная цитата, которая, я думаю, перефразирует то, что я называю пробелом в представлении:
Можно долго спорить о том, какая парадигма обеспечивает наилучшую поддержку для разработки программного обеспечения, но при этом достигается самый естественный, эффективный и действенный пакет разработки, когда он остается в одной парадигме от описания проблемы до ее реализации и доставки.
Вот набор диаграмм, предложенных FAD:
- диаграммы зависимости функций, которые представляют функцию с теми, которые она использует в своей реализации;
- диаграмма зависимостей типов, которая предоставляет один и тот же сервис для типов; и,
- Диаграммы зависимостей модулей, которые представляют взгляды на модульную архитектуру системы.
В разделе 5.1 тезиса ФАД приведено тематическое исследование, которое представляет собой систему для автоматизации производства данных, относящихся к футбольной (футбольной) лиге. Требования являются на 100% функциональными, например, ввод результатов футбола, создание таблиц лиги, таблиц оценок, таблиц посещаемости, перенос игроков между командами, обновление данных после получения новых результатов и т. Д. Никаких упоминаний о том, как FAD работает для решения нефункциональных требований, не задокументировано Помимо заявления о том, что «новые функциональные возможности должны быть разрешены с минимальными затратами», это практически невозможно протестировать.
К сожалению, кроме FAD, я не вижу никаких современных ссылок на языки моделирования (визуальные), которые предлагаются для FP. UML - это еще одна парадигма, поэтому мы должны забыть об этом.
Ответы:
Основные данные структурированы одинаково практически в любой парадигме. Вы будете иметь a
Student
, aCourse
и т. Д., Будь то объект, структура, запись или что-то еще. Разница с ООП заключается не в том, как структурированы данные, а в том, как структурированы функции.На самом деле я нахожу, что функциональные программы гораздо ближе соответствуют тому, как я думаю о проблеме. Например, чтобы спланировать расписание студента на следующий семестр, вы должны подумать о таких вещах, как списки курсов, которые студент закончил, курсы по программе обучения для студентов, курсы, предлагаемые в этом семестре, курсы, для которых студент выполнил предварительные условия, курсы со временем, которое не конфликт и т. д.
Неожиданно становится неясно, какой класс должен создавать и хранить все эти списки. Тем более, когда у вас есть сложные комбинации этих списков. Тем не менее, вы должны выбрать один класс.
В FP вы пишете функции, которые берут студента и список курсов и возвращают отфильтрованный список курсов. Вы можете сгруппировать все такие функции вместе в модуле. Вам не нужно связывать это с тем или иным классом.
Таким образом, ваши модели данных в конечном итоге выглядят более похожими на то, как программисты ООП думают о своих моделях, до того, как они загрязняются классами, у которых нет другой цели, кроме предоставления удобных мест для размещения функций, которые работают с комбинациями других классов. Никаких странных
CourseStudentFilterList
или похожих классов, которые вам всегда нужны в ООП, но которые вы никогда не задумывались в начале разработки.источник
StudentCourseFilterer
чтобы все было под контролемfunc
(так же, как вы ее назвали иIFilter
т. Д.). В общем, в FP вы бы назвали этоfunc
илиf
когда либо,sort
либоfilter
является правильным выбором! Например, при написании функции высшего порядка, которая принимаетfunc
в качестве параметра.Когда я учился на уроках Java много лет назад, мы должны были показать наши решения всему классу, поэтому я увидел, как люди думают; как они решают проблемы логически. Я полностью ожидал, что решения будут сгруппированы вокруг трех или четырех общих решений. Вместо этого я наблюдал, как 30 студентов решили проблему 30 совершенно разными способами.
Естественно, по мере того, как начинающие программисты приобретают опыт, они получают доступ к общим программным шаблонам, начинают использовать эти шаблоны в своем коде, а затем их решения могут объединиться вокруг нескольких оптимальных стратегий. Эти шаблоны образуют технический язык, с помощью которого опытные разработчики могут общаться.
Техническим языком, лежащим в основе функционального программирования, является математика . Соответственно, проблемы, которые наиболее подходят для решения с использованием функционального программирования, являются по существу математическими задачами. По математике я не имею в виду тот тип математики, который вы бы увидели в бизнес-решениях, например сложение и вычитание. Скорее, я говорю о том виде математики, который вы могли бы видеть в Math Overflow, или о типе математики, который вы могли бы видеть в поисковике Orbitz (он написан на Лиспе).
Эта ориентация имеет некоторые важные последствия для функциональных программистов, пытающихся решить реальные проблемы программирования:
Функциональное программирование скорее декларативно, чем обязательно; это касается прежде всего того, чтобы сообщать компьютеру, что делать, а не как это делать.
Объектно-ориентированные программы часто создаются сверху вниз. Создается дизайн класса, и детали заполняются. Функциональные программы часто создаются снизу вверх, начиная с небольших подробных функций, которые объединяются в функции более высокого уровня.
Функциональное программирование может иметь преимущества для создания прототипов сложной логики, создания гибких программ, которые могут органично изменяться и развиваться, и создания программного обеспечения, где первоначальный дизайн неясен.
Объектно-ориентированные программы могут быть более подходящими для бизнес-доменов, поскольку классы, сообщения между объектами и шаблоны программного обеспечения обеспечивают структуру, которая сопоставляется с бизнес-доменом, захватывает его бизнес-аналитику и документирует ее.
Поскольку все практическое программное обеспечение генерирует побочные эффекты (I / O), чисто функциональные языки программирования требуют механизма для создания этих побочных эффектов, оставаясь при этом математически чистыми (монады).
Функциональные программы могут быть более легко доказаны благодаря их математической природе. Система типов Haskell может находить во время компиляции то, чего не может большинство языков OO.
И так далее. Как и во многих вещах в вычислительной технике, объектно-ориентированные языки и функциональные языки имеют различные компромиссы.
Некоторые современные ОО-языки приняли некоторые из полезных концепций функционального программирования, так что вы можете получить лучшее из обоих миров. Linq и языковые функции, которые были добавлены для его поддержки, являются хорошим примером этого.
источник
SafeString
тип для представления строк, которые были экранированы в HTML - и, как правило, больше отслеживают последствия.Я хотел бы подчеркнуть аспект, который я считаю важным и который не был рассмотрен в других ответах.
Прежде всего, я думаю, что разрыв между задачами и решениями может быть больше в голове у программиста, в соответствии с их опытом и концепциями, с которыми они более знакомы.
ООП и ФП рассматривают данные и операции с двух разных точек зрения и обеспечивают разные компромиссы, как уже отмечал Роберт Харви.
Одним из важных аспектов, которыми они отличаются, является способ расширения вашего программного обеспечения.
Рассмотрим ситуацию, в которой у вас есть набор типов данных и набор операций, например, у вас есть разные форматы изображений, и вы поддерживаете библиотеку алгоритмов для обработки изображений.
Функциональное программирование облегчает добавление новых операций в ваше программное обеспечение: вам нужно только локальное изменение в вашем коде, а именно вы добавляете новую функцию, которая обрабатывает различные форматы входных данных. С другой стороны, добавление новых форматов является более сложным: вам нужно изменить все функции, которые вы уже реализовали (не локальное изменение).
Объектно-ориентированный подход симметричен этому: каждый тип данных несет свою собственную реализацию всех операций и отвечает за выбор правильной реализации во время выполнения (динамическая диспетчеризация). Это позволяет легко добавлять новый тип данных (например, новый формат изображения): вы просто добавляете новый класс и реализуете все его методы. С другой стороны, добавление новой операции означает изменение всех классов, которые должны обеспечить эту операцию. Во многих языках это достигается путем расширения интерфейса и адаптации всех классов, реализующих его.
Этот другой подход к расширению является одной из причин, почему ООП более подходит для определенных задач, когда набор операций меняется реже, чем набор типов данных, с которыми работают эти операции. Типичным примером являются ГПИ: у вас есть фиксированный набор операций , которые все виджеты должны реализовать (
paint
,resize
,move
, и т.д.) , и набор виджетов , которые вы хотите расширить.Таким образом, в соответствии с этим измерением, ООП и ФП являются всего лишь двумя особыми способами организации вашего кода. См. SICP , в частности, Раздел 2.4.3, Таблица 2.22 и параграф Передача сообщений .
Подводя итог: в ООП вы используете данные для организации операций, в ФП вы используете операции для организации данных. Каждый подход сильнее или слабее в зависимости от контекста. В общем, ни один из двух не имеет более высокого репрезентативного разрыва между проблемой и решением.
источник
Other
вариант / конструктор в вашем типе данных и дополнительный параметр функции, который должен быть передан всем функциям для обработки другого случая. Это, конечно, неудобно / менее естественно в отношении решения ООП (динамическая диспетчеризация). Таким же образом, шаблон посетителя неуклюжий / менее естественный, чем решение FP (функция более высокого порядка).Большинство функциональных языков не являются объектно-ориентированными. Это не означает, что у них нет объектов (в смысле сложных типов, с которыми связана определенная функциональность). В Haskell, как и в Java, есть списки, карты, массивы, всевозможные деревья и многие другие сложные типы. Если вы посмотрите на модуль Haskell List или Map, вы увидите набор функций, очень похожих на методы в большинстве эквивалентных модулей библиотеки OO-языка. Если вы проверяете код, вы даже найдете похожую инкапсуляцию с некоторыми типами (или, если быть точным, с их конструкторами) и функциями, которые могут использоваться только другими функциями в модуле.
То, как вы работаете с этими типами в Haskell, часто почти не отличается от способа OO. В Хаскеле я говорю
а на яве ты говоришь
Помидор, помидор. Функции Haskell не привязаны к объекту, но тесно связаны с его типом. «Ага, но , - говорите вы, - на Java вызывается метод, длина которого соответствует реальному классу этого объекта». Сюрприз - Haskell тоже делает полиморфизм с классами типов (и другими вещами).
В Haskell, если у меня есть - коллекция целых чисел - не имеет значения, является ли коллекция списком, множеством или массивом, этот код
вернет коллекцию со всеми дублированными элементами. Полиморфизм означает, что будет вызвана соответствующая функция отображения для определенного типа.
Эти примеры, на самом деле, не очень сложные типы, но то же самое относится и к более сложным задачам. Идея о том, что функциональные языки не позволяют моделировать сложные объекты и ассоциировать с ними определенные функции, просто ошибочна.
Между функционалом и ОО-стилем есть важные и существенные различия, но я не думаю, что этот ответ должен касаться их. Вы спросили, мешают ли функциональные языки (или мешают) интуитивному моделированию проблем и задач. Ответ - нет.
источник
FP действительно стремится к сокращению репрезентативного разрыва:
Что-то, что вы увидите много на функциональных языках, - это практика построения языка (используя восходящий дизайн) в Embedded Domain Specific Language (EDSL) . Это позволяет вам разрабатывать средства выражения ваших деловых проблем естественным для вашего домена языком программирования. Хаскелл и Лисп оба гордятся этим.
Часть (если не все) того, что обеспечивает эту способность, заключается в большей гибкости и выразительности в самом базовом языке (ах); с функциями первого класса, функциями высшего порядка, композицией функций, а также в некоторых языках, алгебраическими типами данных (различаемые объединения AKA) и способностью определять операторы *, существует больше возможностей для выражения вещей, чем в OOP, который означает, что вы, вероятно, найдете более естественные способы выразить вещи из вашей проблемной области. (Следует сказать, что многие языки ООП в последнее время применяют многие из этих функций, если не начинать с них.)
* Да, во многих языках ООП вы можете переопределить стандартные операторы, но в Haskell вы можете определить новые!
В моем опыте работы с функциональными языками (в основном, F # и Haskell, немного Clojure и немного Lisp и Erlang) мне легче сопоставить проблемное пространство с языком, чем с OOP - особенно с алгебраическими типами данных, который я считаю более гибким, чем классы. Когда я начинал с FP, особенно с Haskell, меня бросило в тупик то, что я должен был думать / работать на более высоком уровне, чем я привык в императивных или ООП-языках; Вы можете столкнуться с этим немного.
источник
Как сказал Никлаус Вирт, «Алгоритмы + структуры данных = программы». Функциональное программирование - это способ организации алгоритмов и мало что говорит о способах организации структур данных. Действительно, существуют языки FP как с изменяемыми (Lisp), так и с неизменяемыми (Haskell, Erlang) переменными. Если вы хотите сравнить и сопоставить FP с чем-то, вы должны выбрать императивное (C, Java) и декларативное (Prolog) программирование.
С другой стороны, ООП - это способ построения структур данных и привязывания к ним алгоритмов. FP не мешает вам создавать структуры данных, подобные ООП. Если вы мне не верите, взгляните на объявления типов в Haskell. Однако большинство языков FP согласны с тем, что функции не принадлежат структурам данных и должны находиться в одном и том же пространстве имен. Это сделано для того, чтобы упростить построение новых алгоритмов с помощью композиции функций. В самом деле, если вы знаете, какой ввод принимает функция и какой вывод она производит, почему это должно иметь значение, к какой структуре данных она тоже принадлежит? Например, почему
add
функция должна вызываться для экземпляра типа Integer и передавать аргумент вместо простой передачи двух аргументов Integer?Поэтому я не понимаю, почему FP должен усложнять понимание решений в целом, и я не думаю, что это так или иначе. Однако имейте в виду, что опытный императивный программист наверняка найдет функциональные программы сложнее для понимания, чем императивные, и наоборот. Это похоже на дихотомию Windows - Linux, когда люди, которые потратили 10 лет на то, чтобы освоить среду Windows, находят Linux трудным после месяца использования, а те, кто привык к Linux, не могут достичь той же производительности в Windows. Следовательно, «репрезентативный разрыв», о котором вы говорите, очень субъективен.
источник
if you know what input a function takes and what output it produces, why should it matter which data structure it belongs too?
Это очень похоже на сплоченность, что важно для любой модульной системы. Я бы сказал, что незнание того, где найти функцию, затруднит понимание решения, что связано с большим разрывом в представлении. Многие ОО-системы имеют эту проблему, но это из-за плохого дизайна (низкая когезия). Опять же, проблема пространства имен выходит за рамки моего опыта в FP, так что, возможно, это не так плохо, как кажется.