За многие годы ОО-программирования я понял, что такое дискриминационные союзы, но я никогда не пропускал их. Недавно я занимался некоторым функциональным программированием на C #, и теперь я продолжаю желать, чтобы они у меня были. Это сбивает с толку меня, потому что, на первый взгляд, концепция дискриминируемых союзов кажется совершенно независимой от дихотомии функционал / OO.
Есть ли в функциональном программировании что-то, что делает дискриминационные союзы более полезными, чем они были бы в ОО, или же, заставляя себя анализировать проблему «лучше», я просто поднял свои стандарты и теперь требую лучшего модель?
Ответы:
Дискриминационные союзы действительно сияют в сочетании с сопоставлением с образцом, где вы выбираете различное поведение в зависимости от случаев. Но эта модель принципиально противоположна принципам чистого ОО.
В чистом ОО различия в поведении должны определяться самими типами (объектами) и инкапсулироваться. Таким образом, эквивалентность сопоставлению с образцом будет заключаться в вызове одного метода для самого объекта, который затем перегружается рассматриваемыми подтипами для определения другого поведения. Проверка типа объекта извне (что и делает сопоставление с образцом) считается антипаттерном.
Принципиальное отличие состоит в том, что данные и поведение являются отдельными в функциональном программировании, тогда как данные и поведение объединяются в ОО.
Это историческая причина. Язык, подобный C #, развивается от классического ОО-языка к языку с множеством парадигм, добавляя все больше и больше функций.
источник
List<A>
это методB Match<B>(B nil, Func<A,List<A>,B> cons)
. Например, это именно тот шаблон, который Smalltalk использует для логических значений. Это также в основном то, как Scala справляется с этим. Использование нескольких классов является деталью реализации, которую не нужно раскрывать.isEmpty
метод, который проверяет, является ли ссылка на следующий узел нулевой.Запрограммировавшись на Паскале и в Аде, прежде чем изучать функциональное программирование, я не ассоциирую дискриминационные союзы с функциональным программированием.
Дискриминационные союзы являются в некотором роде двойным наследством. Первые позволяют легко добавлять операции с фиксированным набором типов (в объединении), а наследование позволяет легко добавлять типы с фиксированным набором операций. (Как легко добавить оба, называется проблемой выражения ; это особенно трудная проблема для языков со статической системой типов.)
Из-за акцента ОО на типах и двойного акцента функционального программирования на функции, функциональные языки программирования имеют естественное сходство с типами объединения и предлагают синтаксические структуры для облегчения их использования.
источник
Методы императивного программирования, которые часто используются в ОО, часто опираются на два шаблона:
null
чтобы указать «нет значения» или сбой.Функциональная парадигма обычно избегает их обоих, предпочитая возвращать составной тип, который указывает на причину успеха / неудачи или значение / нет значения.
Дискриминационные союзы отвечают всем этим сложным типам. Например, в первом случае вы можете вернуть
true
или какую-то структуру данных, описывающую сбой. Во втором случае - объединение, содержащее значение, илиnone
иnil
т. Д. Во втором случае настолько распространено, что многие функциональные языки имеют встроенный тип типа «возможно» или «опция», представляющий это значение / нет объединения.Переключаясь на функциональный стиль, например, с помощью C #, вы быстро обнаружите необходимость в этих составных типах.
void/throw
иnull
просто не чувствую себя хорошо с таким кодом. И дискриминационные союзы (DUs) хорошо отвечают всем требованиям. Таким образом, вы обнаружили, что хотите их, как и многие из нас.Хорошая новость заключается в том, что существует множество библиотек, которые моделируют DU, например, в C # (посмотрите на мою собственную библиотеку Succinc <T>, например).
источник
Типы суммы, как правило, будут менее полезны в основных языках ОО, поскольку они решают проблему, аналогичную типу ОО. Один из способов взглянуть на них состоит в том, что они оба обрабатывают подтипы, но OO - это
open
то, что можно добавить произвольные подтипы к родительскому типу, а типы сумм -closed
то есть, кто заранее определяет, какие подтипы допустимы.Теперь многие ОО-языки сочетают подтипы с другими понятиями, такими как унаследованные структуры, полиморфизм, типизация ссылок и т. Д., Чтобы сделать их в целом более полезными. Как следствие, они, как правило, требуют больше усилий для настройки (с классами и конструкторами и так далее), поэтому обычно их не используют для таких вещей, как
Result
s иOption
s и так далее, пока универсальная типизация не станет обычной.Я бы также сказал, что акцент на реальных отношениях, которые большинство людей изучило, когда они начали программирование ОО, например, Dog isa Animal, означал, что Integer isa Result или Error isa Result кажутся немного чуждыми. Хотя идеи довольно похожи.
Что касается того, почему функциональные языки могут предпочесть закрытую типизацию открытой, то возможной причиной является то, что они предпочитают сопоставление с образцом. Это полезно для полиморфизма функций, но также очень хорошо работает с закрытыми типами, поскольку компилятор может статически проверять, что сопоставление охватывает все подтипы. Это может сделать язык более последовательным, хотя я не верю, что есть какая-то внутренняя выгода (я могу ошибаться).
источник
sealed
означает «может быть расширен только в одном модуле компиляции», что позволяет закрывать набор подклассов во время разработки.Swift счастливо использует дискриминационные союзы, за исключением того, что называет их «перечислениями». Перечисления являются одной из пяти фундаментальных категорий объектов в Swift: класс, структура, перечисление, кортеж и замыкание. Опционы Swift - это перечисления, которые являются различающими объединениями, и они абсолютно необходимы для любого кода Swift.
Поэтому предположение, что «дискриминационные союзы связаны с функциональным программированием» неверно.
источник