Чому дискримінаційні спілки пов'язані з функціональним програмуванням?


30

Протягом багатьох років програмування ОО я зрозумів, що таке дискримінаційні спілки, але ніколи їх не пропускав. Нещодавно я займався деяким функціональним програмуванням на C #, і тепер я вважаю, що хочу бачити їх. Це мене бентежить, оскільки, дивлячись на це, концепція дискримінованих спілок виглядає цілком незалежною від функціональної / дихотомії ОО.

Чи є щось притаманне функціональному програмуванню, що робить дискриміновані спілки більш корисними, ніж вони були б в ООС, чи це, змушуючи себе аналізувати проблему «кращим» способом, я просто покращив свої стандарти і тепер вимагаю кращого модель?


Проблема з виразом en.wikipedia.org/wiki/Expression_problem може бути актуальною
xji

Це насправді не належна відповідь на питання, тому я відповім як коментар замість цього, але мова програмування Цейлона має типи об'єднання, і вони, схоже, переповнюються на інші OO / змішані мови парадигми - мені приходять TypeScript і Scala. Також переклади на мові Java можуть використовуватися як своєрідна реалізація дискримінованих спілок.
Roland Tepp

Відповіді:


45

Дискримінація профспілок справді світиться в поєднанні зі збігом моделей, де ви вибираєте різну поведінку залежно від випадків. Але ця закономірність принципово антитетична чистим принципам ОО.

У чистому OO різницю в поведінці слід визначати самими типами (об'єктами) та інкапсулювати. Таким чином, еквівалентність відповідності шаблону полягала б у виклику одного методу на самому об'єкті, який потім перевантажується відповідними підтипами для визначення різної поведінки. Перевірка типу об’єкта ззовні (саме те, що відповідає узгодженню шаблону) вважається антипаттерном.

Принципова відмінність полягає в тому, що дані та поведінка є окремими у функціональному програмуванні, тоді як дані та поведінка інкапсульовані разом у ОО.

Це історична причина. Мова на зразок C # розвивається від класичної мови OO до мови багатопарадигми, включаючи все нові й нові функції.


6
Тип дискримінації об'єднання / суми не схожий на дерево спадкування або кілька класів, що реалізують інтерфейс; це один тип з багатьма видами значень. Вони також не перешкоджають інкапсуляції; клієнту не потрібно знати, що у вас є кілька видів цінностей. Розглянемо пов'язаний список, який може бути або порожнім вузлом, або значенням і посиланням на інший вузол. Без типів суми ви в будь-якому разі зламаєте дискримінований об'єднання, маючи змінні значення та посилання, але обробляючи об'єкт з нульовою посиланням як порожній вузол і роблячи вигляд, що змінна значення не існує.
Довал

2
Як правило, ви включаєте змінні для всіх можливих типів значень в одному класі, плюс якийсь прапор чи перерахунок, щоб повідомити, яке значення має цей екземпляр, і танцюєте навколо змінних, які не відповідають цьому добрий.
Доваль

7
@Doval Існує "стандартне" кодування алгебраїчного типу даних в класи за допомогою інтерфейсу / абстрактного базового класу, що представляє тип загального типу та наявність підкласу для кожного випадку типу. Для обробки відповідності шаблонів у вас є метод, який приймає функцію для кожного випадку, тому для списку, який ви мали б мати в інтерфейсі верхнього рівня, List<A>метод B Match<B>(B nil, Func<A,List<A>,B> cons). Наприклад, це саме той візерунок, який Smalltalk використовує для булів. Це також в основному, як Скала справляється з цим. Те, що використовується декілька класів, - це детальна інформація про реалізацію, яку не потрібно піддавати впливу.
Дерек Елкінс

3
@Doval: Явна перевірка нульових посилань насправді теж не вважається ідіоматичним OO.
JacquesB

@JacquesB Нульова перевірка - це деталь реалізації. Для клієнта пов'язаного списку зазвичай існує isEmptyметод, який перевіряє, чи посилання на наступний вузол є нульовим.
Довал

35

Програмувавшись у Паскалі та Ада, перш ніж вивчати функціональне програмування, я не пов'язую дискриміновані спілки з функціональним програмуванням.

Дискримінаційні спілки є певним чином подвійним у спадщині. Перші дозволяють легко додавати операції на фіксованому наборі типів (ті, що в союзі), а успадкування дозволяє легко додавати типи з фіксованим набором операцій. (Як легко додати обидва, це називається проблемою вираження ; це особливо важка проблема для мов із системою статичного типу.)

Завдяки акцентуванню ОО на типи та подвійному наголосу функціонального програмування на функціях, функціональні мови програмування мають природну спорідненість до типів об'єднання та пропонують синтаксичні структури для полегшення їх використання.


7

Імперативні методи програмування, як часто використовуються в ОО, часто покладаються на дві схеми:

  1. Успіх або киньте виняток,
  2. Поверніться, nullщоб вказати "немає значення" або відмови.

Функціональна парадигма, як правило, уникає обох, віддаючи перевагу поверненню типу сполуки, що вказує на причину успіху / відмови або значення / немає значення.

Дискримінація профспілок відповідає законопроекту для цих складних типів. Наприклад, у першому випадку ви можете повернути trueабо якусь структуру даних, яка описує збій. У другому випадку, союз , який містить значення, або none, і nilт.д. Другий випадок є настільки поширеним, що багато функціональні мови мають «може бути» або типу «варіант» вбудований , щоб представити , що значення / немає союзу.

При переході на функціональний стиль з, наприклад, C #, ви швидко знайдете потребу в цих складових. void/throwі nullпросто не відчуваю себе правильно з таким кодом. І дискриміновані профспілки добре підходять до законопроекту. Таким чином, ви виявили, що бажаєте їх, як і багато хто з нас.

Хороша новина полягає в тому, що там є багато бібліотек, які моделюють DU, наприклад, C # (перегляньте, наприклад, мою власну бібліотеку Succinc <T> ).


2

Типи суми, як правило, менш корисні для основних мов ОО, оскільки вони вирішують проблему, подібну до підтипу OO. Один із способів дивитися на них полягає в тому, що вони обидва обробляють openпідтипи, але OO - тобто можна додати довільні підтипи до батьківського типу, а типи суми, closedтобто один визначає наперед, які підтипи є дійсними.

Зараз багато мов ОО поєднують підтипи з іншими поняттями, такими як успадковані структури, поліморфізм, референтне введення тощо, щоб зробити їх загалом кориснішими. Наслідком цього є те, що вони, як правило, займаються більшою роботою над створенням (з класами та конструкторами та ін.), Так що, як правило, не використовуються для таких речей, як Results та Options тощо, поки загальне введення тексту не стане загальним.

Я б також сказав, що зосередження уваги на реальних відносинах, про які більшість людей дізналися, коли вони розпочали програмування OO, наприклад, Dog isa Animal, означало, що Integer isa Result або Error isa Result здаються трохи чужими. Хоча ідеї досить схожі.

Щодо того, чому функціональні мови можуть вважати за краще закрите введення тексту перед відкритим введенням, одна з можливих причин полягає в тому, що вони, як правило, віддають перевагу відповідності шаблону. Це корисно для функціонального поліморфізму, але воно також дуже добре працює із закритими типами, оскільки компілятор може статично перевірити, що відповідність охоплює всі підтипи. Це може змусити мову відчувати себе більш послідовно, хоча я не вірю, що є якась притаманна користь (я можу помилитися).


До речі: Скала закрив спадщину. sealedозначає "можна розширити лише в одному і тому ж блоці компіляції", що дозволяє закрити набір підкласів під час проектування.
Йорг W Міттаг

-3

Свіфт із задоволенням використовує дискримінаційні спілки, за винятком того, що називає їх "перелюдами". Енуми - одна з п’яти основних категорій об'єктів Свіфта, які є класом, структурою, перерахунком, кортежем та закриттям. Факультативи Swift - це переліки, які є дискримінаційними спілками, і вони абсолютно необхідні для будь-якого коду Swift.

Отже, припущення про те, що "дискримінаційні спілки пов'язані з функціональним програмуванням" є неправильним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.