Несколько месяцев назад я вернулся в Clojure по работе в Cognician. Очень интересно использовать на регулярной основе несколько контрастирующих языков программирования. На данном этапе у меня Clojure и F #. Вы действительно каждый день заново ощущаете уникальные сильные и слабые стороны каждого языка.
Одна из вещей, которые мне нравятся в Clojure, - это то, насколько легко создать коллекцию с различными типами, а также мощность, которая дает вам беспрепятственный перенос и преобразование данных. В какой-то степени это будет верно для любого нетипизированного языка, хотя сплоченность структур данных Clojure гораздо глубже, чем в большинстве других языков. Время от времени я все еще натыкаюсь на некоторые окопы системы типов F #, где мне приходится немного бороться с ней, чтобы заставить ее делать то, что я хочу. Я верю, что это будет еще более верно в отношении других типизированных языков, поскольку я считаю F # неплохим. Хотя F # уже кажется довольно динамичным благодаря довольно хорошему выводу типов, в такие моменты я не могу не задуматься над способами использования F #, чтобы он вел себя больше как динамический язык? Со стороны Clojure разработчики задают аналогичные вопросы, но только о том, как получить некоторые из преимуществ типизированных языков, поэтому у нас есть такие вещи, как clojure.spec, Schema и Типизированный Clojure .
Все вышесказанное привело меня к тому, что недавно я осознал силу дискриминируемых союзов F #, скрытых у всех на виду. Рассмотрим следующее размеченное объединение и функцию:
type RestRes<'a> = | GetAll of (unit -> 'a list) | Create of ('a -> 'a) | GetById of (int64 -> 'a option) | IsExists of (int64 -> bool) | Update of ('a -> 'a) | UpdateById of (int64 -> 'a -> 'a) | Delete of (int64 -> unit) let inline rest resourceName (resources: RestRes< 'a> list) = ...
На первый взгляд это не так уж и много. Но подумайте еще раз, и вы поймете, что это позволяет коллекции RestRes ‹‘ a › содержать любой из ее типов. Итак, что вы говорите, вы можете добиться того же с помощью наследования. Что ж, дискриминируемые союзы более гибкие, чем наследование, потому что вы можете добавить один и тот же тип к нескольким различаемым объединениям. Это также безопаснее, потому что никакие функции от родительского элемента не проникают в дочерние элементы. Это всего лишь структура для интеграции различных типов, а не их поведения.
Размеченное объединение может легко скрыть ваши типы, когда они вам не нужны, а затем вы можете использовать сопоставление с образцом (деструктуризация в Clojure), чтобы раскрыть их, когда вы хотите отфильтровать для определенных типов:
((match method with | GetAll(getAll) -> ... | Create(create) -> ... | Update(update) -> ... | _ -> ...), match method with | GetById(getById) -> ... | UpdateById(updateById) -> ... | Delete(deleteById) -> ... | _ -> ...)
Итак, в приведенном выше примере я использую выражения соответствия для создания кортежа с двумя членами; один для методов by-Id и один для других. Но приятно то, что он позволяет мне вызывать функцию с кодом, который выглядит следующим образом:
rest "portfolio" [ GetAll(portfolio) Create(saveSecurity) UpdateById(saveSecurityById) ]
Вы можете аккуратно создать список с любым количеством различных типов методов отдыха. Остальная функция позаботится о фильтрации списка и без труда выберет типы, с которыми нужно работать. Тем не менее, вам нигде не нужно беспокоиться о типе различаемого объединения при вызове функции rest. Объединение незаметно работает в фоновом режиме, чтобы вы могли использовать разные типы, даже не осознавая этого. Список F # теперь ведет себя больше как его аналог Clojure, чем обычный список одного типа.
Итак, теперь представьте, что у вас есть модель предметной области с множеством различных записей, кортежей и других типов. Допустим, вам нужна функция, которая должна иметь возможность работать с коллекцией со смешанными типами домена или возвращать ее. Теперь вы можете легко использовать размеченное объединение DomainModel для достижения этой цели, не ограничивая типы в модели предметной области принадлежностью к любому количеству категорий типов.