Есть классическая статья под названием «Критерии для использования при декомпозиции систем на модули», которую я только что прочитал впервые. Это имеет смысл для меня и, вероятно, является одной из тех статей, на которых основывается ООП. Его вывод:
Мы попытались продемонстрировать на этих примерах, что почти всегда неправильно начинать декомпозицию системы на модули на основе блок-схемы. ... Каждый модуль предназначен для того, чтобы скрыть такое решение от других.
По моему необразованному и неопытному мнению, функциональное программирование принимает прямо противоположный совет этой статьи. Я понимаю, что функциональное программирование делает поток данных идиоматическим. Данные передаются от функции к функции, каждая функция тщательно осведомлена о данных и «меняет их» на своем пути. И я думаю, что видел выступление Рича Хикки, в котором он говорит о том, что сокрытие данных переоценено или ненужно или что-то в этом роде, но я точно не помню.
- Сначала я хочу знать, правильна ли моя оценка. Парадигма FP и эта статья философски не согласны?
- Предполагая, что они не согласны, как FP "компенсирует" отсутствие скрытия данных? Возможно, они жертвуют сокрытием данных, но получают X, Y и Z. Я хотел бы знать причину, почему X, Y и Z считаются более выгодными, чем сокрытие данных.
- Или, если они не согласны, возможно, FP считает, что сокрытие данных - это плохо. Если так, почему он считает, что сокрытие данных плохо?
- Предполагая, что они согласны, я хотел бы знать, что такое реализация сокрытия данных в FP. Это очевидно в ООП. У вас может быть
private
поле, к которому никто за пределами класса не может получить доступ. Там нет очевидной аналогии этого для меня в FP. - Я чувствую, что есть другие вопросы, которые я должен задавать, но я не знаю, должен ли я задавать. Не стесняйтесь отвечать на них тоже.
Обновить
Я нашел этот разговор Нила Форда, в котором есть очень актуальный слайд. Я вставлю скриншот здесь:
источник
Ответы:
Упомянутая вами статья посвящена модульности в целом и в равной степени относится к структурированным, функциональным и объектно-ориентированным программам. Ранее я слышал об этой статье от кого-то, кто был большим парнем из ООП, но я прочитал ее как статью о программировании в целом, а не как оОП-специфичную. Есть известная статья о функциональном программировании, Почему функциональное программирование имеет значение , и первое предложение заключения гласит: «В этой статье мы утверждали, что модульность является ключом к успешному программированию». Таким образом, ответ на (1) - нет.
Хорошо спроектированные функции не предполагают больше о своих данных, чем им нужно, поэтому часть о «глубоком осознании данных» неверна. (Или, по крайней мере, так же неправильно, как и в случае ООП. Вы не можете программировать строго на высоком уровне абстракции и игнорировать все детали навсегда в любой парадигме. В конце концов, некоторая часть программы действительно должна знать о конкретные детали данных.)
Сокрытие данных - это специальный термин ООП, и оно не совсем то же самое, что скрытие информации, обсуждаемое в статье. Информация, скрывающаяся в статье, касается дизайнерских решений, которые было трудно принять или которые могут измениться. Не каждое проектное решение о формате данных сложно или вероятно изменить, и не каждое решение, которое трудно или вероятно изменить, касается формата данных. Лично я не понимаю, почему ОО-программисты хотят, чтобы все было объектом. Иногда простая структура данных - это все, что вам нужно.
Изменить: я нашел соответствующую цитату из интервью с Рич Хикки .
источник
Не совсем, но это добавило к дискуссии, особенно для практиков, которые в то время были обучены разлагать системы, используя первые критерии, которые он описывает в статье.
Нет. Более того, на мой взгляд, ваше описание того, как выглядит FP-программа, ничем не отличается от любого другого, использующего процедуры или функции:
... за исключением части "интимности", поскольку вы можете (и часто делаете) иметь функции, работающие с абстрактными данными, именно для того, чтобы избежать интимности. Таким образом, у вас есть некоторый контроль над этой «интимностью», и вы можете регулировать ее по своему усмотрению, устанавливая интерфейсы (то есть функции) для того, что вы хотите скрыть.
Таким образом, я не вижу причин, по которым мы не смогли бы следовать критериям скрытия информации Parnas при использовании функционального программирования и в конечном итоге реализовать индекс KWIC с теми же преимуществами, что и его вторая реализация.
Что касается данных, вы можете разработать абстракции данных и абстракции типов данных, используя FP. Любые из них скрывают конкретные структуры и манипуляции с этими конкретными структурами, используя функции в качестве абстракций.
РЕДАКТИРОВАТЬ
Растет число утверждений о том, что «сокрытие данных» в контексте FP не так полезно (или ООП-иш (?)). Итак, позвольте мне напечатать здесь очень простой и понятный пример из SICP:
Предположим, что ваша система должна работать с рациональными числами. Один из способов их представления - это пара или список из двух целых чисел: числителя и знаменателя. Таким образом:
Если вы игнорируете абстракцию данных, скорее всего вы получите числитель и знаменатель, используя
car
иcdr
:Следуя этому подходу, все части системы, которые манипулируют рациональными числами, будут знать, что рациональное число - это
cons
- они будутcons
числами создавать рациональные числа и извлекать их, используя операторы списка.Одна из проблем, с которой вы можете столкнуться, - это необходимость сокращения рациональных чисел в уменьшенном виде - изменения потребуются по всей системе. Кроме того, если вы решите уменьшить во время создания, позже вы можете обнаружить, что сокращение при доступе к одному из рациональных терминов лучше, приводя к другому полномасштабному изменению.
Другая проблема заключается в том, что, если гипотетически, альтернативное представление для них предпочтительнее, и вы решаете отказаться от
cons
представления - снова полномасштабное изменение.Любые разумные попытки справиться с этими ситуациями, скорее всего, начнут скрывать представление рациональности за интерфейсами. В конце вы можете получить что-то вроде этого:
(make-rat <n> <d>)
возвращает рациональное число, числитель которого является целым числом,<n>
а знаменатель - целым числом<d>
.(numer <x>)
возвращает числитель рационального числа<x>
.(denom <x>)
возвращает знаменатель рационального числа<x>
.и система больше не будет (и не должна) знать, из чего сделаны рациональные решения. Это происходит потому
cons
,car
иcdr
не присущи рациональные числа, ноmake-rat
,numer
иdenom
это . Конечно, это может быть система FP. Таким образом, «сокрытие данных» (в данном случае более известное как абстракция данных или попытка инкапсулировать представления и конкретные структуры) представляет собой актуальную концепцию и метод, широко используемый и исследуемый, будь то в контексте ОО, функционального программирования или без разницы.И дело в том ... хотя можно попытаться провести различие между тем, какой «вид сокрытия» или инкапсуляция они выполняют (скрывают ли они проектное решение, структуры данных или алгоритмы - в случае процедурных абстракций), все они имеют одинаковую тему: они мотивированы одним или несколькими пунктами, которые Парнас сделал явными. То есть:
Приведенный выше пример взят из книги SICP, поэтому для полного обсуждения и представления этих концепций в книге я настоятельно рекомендую ознакомиться с главой 2 . Я также рекомендую ознакомиться с абстрактными типами данных в контексте FP, что приводит к другим проблемам.
источник
Ваша вера в то, что в функциональном программировании отсутствует сокрытие данных, неверна. Это просто другой подход к сокрытию данных. Одним из наиболее распространенных способов скрытия данных в функциональном программировании является использование полиморфных функций, которые принимают функцию в качестве аргумента. Например, эта функция
может видеть только внешнюю структуру данных (то есть, что это список), он не может видеть ничего о данных, которые содержит список, и может работать с данными только через одну функцию, которая ему передана.
Функция, переданная в качестве аргумента, аналогична общедоступному методу для типа данных, который содержится в списке. Он предоставляет ограниченный способ работы с данными, но не раскрывает внутреннюю работу типа данных.
источник
Я собираюсь нанести удар по конечности и сказать, что концепция в ФП не так важна, как в ОО.
ТЛ; др; Смысл сокрытия данных заключается в том, чтобы обеспечить соблюдение обязанностей там, где они должны быть, и чтобы у вас не было сторонних участников, которые возятся с данными, о которых они не знают. В FP данные генерируются с помощью выражений, и таким образом вы не можете связываться с данными, потому что это не изменяемые свойства, а просто составные вычисления, которые полностью изменяют правила игры.
По моему опыту с FP; которые, по общему признанию, незначительны, я склонен находить резкий контраст с ОО в том, что обозначает хорошее / общее моделирование данных.
Этот контраст заключается в том, что в ОО в целом вы моделируете вещи для представления ваших данных. Обязательная аналогия с автомобилем:
OO
Здесь следует обратить внимание на то, что когда вы моделируете вещи в формате ОО, все сводится к представлению вещей как данных. У вас есть объекты со свойствами, многие из которых являются объектами с большим количеством свойств. У вас есть несколько методов, привязанных к этим объектам, но все, что они на самом деле делают, - это обычно изменяют свойства объектов таким образом, и это опять-таки очень ориентированное на данные моделирование; то есть вы моделируете свои данные для взаимодействия с ориентацией на их структурирование, чтобы сделать доступными все точки ваших данных, чтобы потребители могли так или иначе изменять данные.
FP
Большая разница между OO и FP, которая постоянно поражает меня, заключается в том, как я говорил выше, как вы моделируете данные. В ОО, как упоминалось выше, вы моделируете данные как данные, в ФП вы моделируете данные в виде вычислений, выражений, алгоритмов, это больше о моделировании действий ваших данных, чем о фактах. Подумайте о базовом моделировании данных в математике, это всегда о получении уравнения, которое может генерировать ваши данные, которое моделирует ваши данные как деятельность, которая их вызывает, в отличие от ОО, моделирование предлагает способ представления данных, которые у вас есть. Это большая часть различия между FP и OO.
Помните, что в течение долгого времени LISP, один из основополагающих языков FP, жил с очень небольшим количеством примитивных типов данных. Это работает, потому что подход заключается не столько в моделировании сложных представлений ваших данных, сколько в вычислениях, которые генерируют и выражают поведение вашей системы.
Когда я начинаю писать некоторый код на FP, я начинаю с написания кода, который что-то делает, тогда как, когда я начинаю писать код в ОО, я начинаю с написания моделей, которые что-то описывают. Действие вещей скрыто в ФП как выражение, а действие дел раскрывается в ОО путем описания с данными, скрывая эти данные, ограничивая указанную экспозицию.
Возвращаясь к рассматриваемому вопросу, что FP говорит о сокрытии данных, оценивает это или не соглашается с этим или нет?
Я говорю, что это не имеет значения, в ОО ваши данные являются внутренностями и важными частями вашей программы, которые должны быть скрыты от вмешательства. В FP все внутренности и знания вашей системы скрыты в алгоритмах и вычислениях, которые выражают систему. Они по определению более или менее неизменны, единственный способ изменить выражения вычислений - это что-то вроде макросов, но даже тогда вы сами - определения мутаций, которые сами по себе не могут быть изменены.
источник
Здесь есть какой-то парадокс. Хотя функциональное программирование сосредоточено на функциях и зачастую имеет функции, которые работают непосредственно с примитивными типами данных, оно, как правило, скрывает больше данных, чем объектно-ориентированное программирование.
Как это так? Подумайте о хорошем интерфейсе OO, который скрывает лежащие в основе данные - возможно, коллекции (я пытаюсь выбрать что-то почти вездесущее). Вам может не потребоваться знать базовый тип объектов в коллекции или тип объекта, реализующего коллекцию, если вы знаете, что коллекция реализует, скажем, IEnumerable. Итак, у вас есть данные, скрывающиеся.
В функциональном программировании вы можете написать функцию, которая эффективно работает с интерфейсом IEnumerable, но работает с примитивным типом данных (или с любым типом данных). Но что, если тип никогда не реализует методы IEnumerable? Вот ключ, вы всегда можете иметь «методы», которые формируют необходимые части «интерфейса», которые будут передаваться в вашу функцию. Или вы можете объединить функции с данными и сделать что-то вроде OO.
Обратите внимание, что в любом случае вы не будете скрывать меньше данных, чем в OO. Моя общая функция, которая работает с любым типом, явно не имеет доступа к данным этого типа - это происходит внутри функций, передаваемых в качестве параметров в общую функцию, но общая функция никогда не заглядывает внутрь этих функций, чтобы увидеть данные.
Итак, что касается вашего пункта 1, я не думаю, что FP и статья действительно не согласны. Я не думаю, что ваша характеристика FP, не скрывающая данные, верна. Конечно, можно реализовать дизайн, который автор предпочел в FP.
Что касается пункта 4 (2 и 3 не имеет смысла отвечать, учитывая то, что я сказал для пункта 1), то это меняется. Это также варьируется в ОО-языках, и во многих частных полях, согласно соглашению, является закрытым, а не обязательным для языка.
источник
Во-первых, спасибо за ссылку на эту замечательную статью, я до сих пор не знал об этом, и она дала мне отличную информацию о некоторых вещах, которые я обсуждал с некоторыми другими разработчиками программного обеспечения из сообщества в последние годы. Вот мое мнение об этом:
Проектирование FP очень сильно фокусируется на потоке данных (что, на мой взгляд, не так плохо, как может подразумеваться в статье). Если это полное «разногласие», то можно поспорить.
ИМХО это не компенсирует. Увидеть ниже.
Я не думаю, что большинство пользователей или дизайнеров FP чувствуют или думают таким образом, см. Ниже.
Суть в том, что вы, вероятно, видели так много ООП-систем, реализованных нефункционально, что вы считаете, что ООП не функционирует. И это заблуждение: IMHO OOP и FP в основном ортогональны, и вы можете идеально построить функциональные OO-системы, что дает вам очевидный ответ на ваш вопрос. Классическая «объектная» реализация в FP выполняется с использованием замыканий , и если вы хотите, чтобы объекты использовались в функциональной системе, ключевым моментом является их неизменность.
Таким образом, для создания больших систем, IMHO, вы можете создавать модули, классы и объекты, используя концепции ОО, точно так же, как описано в разделе «Модуляризация 2» в статье, не выходя из «пути FP». Вы будете использовать концепцию модуля вашего любимого языка FP, сделайте неизменными все ваши объекты и используйте «лучшее из обоих миров».
источник
TL; DR : нет
Парадигма FP и эта статья философски не согласны?
Нет, это не так. Функциональное программирование является декларативным, то есть «стилем построения структуры и элементов компьютерных программ, который выражает логику вычислений без описания потока управления». Это меньше похоже на следование блок-схеме и больше похоже на создание правил, позволяющих потоку возникать самостоятельно.
Процедурное программирование намного ближе к кодированию блок-схемы, чем функциональное программирование. Из этого следует, что преобразования, которые происходят, и кодируют эти преобразования в процедуры, которые выполняются по порядку, точно так же, как описывает поток в блок-схеме.
Скрытие данных
источник