#f# #discriminated-union
#f# #дискриминируемый-союз
Вопрос:
Общая структура типов и использование в моем текущем F# работают очень хорошо. Тем не менее, я хочу получить некоторую перспективу, если я делаю что-то неправильно или следую какому-то анти-шаблону. Я действительно очень часто обнаруживаю, что, по сути, ожидаю определенного типа в определенной логике, который извлекается из более общего типа, представляющего собой дискриминированное объединение, объединяющее множество различных типов, которые все следуют уровням общей обработки.
По сути, мне нужны конкретные версии этой функции:
'GeneralDiscriminatedUnionType -gt; 'SpecificCaseType
Я ловлю себя на том, что повторяю множество утверждений, подобных следующему:
let checkPromptUpdated (PromptUpdated prompt) = prompt
Это самый простой способ, который я нашел для этого; однако у каждого из них есть действительное предупреждение компилятора, которое имеет смысл, что может возникнуть проблема, если функция вызывается с типом, отличным от ожидаемого. Это справедливо, но у меня пока их от 40 до 50 штук.
Поэтому я начал пробовать следующее, что на самом деле лучше, потому что это вызвало бы допустимое исключение с неправильным использованием (оба они одинаковы).:
let checkPromptUpdated input = match input with | PromptUpdated prompt -gt; prompt | _ -gt; invalidOp "Expecting Prompt" let checkPromptUpdated = function | PromptUpdated prompt -gt; prompt | _ -gt; invalidOp "Expecting Prompt"
Тем не менее, это выглядит намного запутаннее, и я пытаюсь выяснить, есть ли у кого-нибудь какие-либо предложения, прежде чем я начну все это безобразие.
Есть ли какой-то способ применить эту более широкую логику к более общей функции, которая затем позволила бы мне написать это в 50-100 раз более чистым, прямым и читаемым способом?
Этот вопрос-всего лишь вопрос попытки написать более чистый код.
Это пример DU, для которого я пытаюсь написать функции, чтобы иметь возможность извлекать определенные типизированные значения из обращений:
type StateEvent = | PromptUpdated of Prompt | CorrectAnswerUpdated of CorrectAnswer | DifficultyUpdated of Difficulty | TagsUpdated of Tag list | NotesUpdated of Notes | AuthorUpdated of Author
Ответ №1:
Если checkPromptUpdated
функция работает только с событиями, которые имеют отношение к PromptUpdated
делу, то я думаю, что лучший дизайн заключается в том, что функция должна принимать только значение типа Prompt
(вместо значения типа StateEvent
) в качестве аргумента:
let checkPromptUpdated prompt = // do whatever checks you need using 'prompt'
Конечно, это означает, что сопоставление шаблонов будет перенесено из этой функции в функцию, которая ее вызывает, или далее — в место, где вы действительно получаете StateEvent
и должны обрабатывать все остальные случаи. Но это именно то, что вам нужно — как только вы сопоставите шаблон события, вы сможете работать с более конкретными типами, такими как Prompt
.
Комментарии:
1. Спасибо, Томас. Это направление имеет смысл, и я собираюсь попытаться ориентироваться на более широкую логику, чтобы соответствовать этому. Это действительно выгодно благодаря возможности обеспечить исчерпывающее сопоставление шаблонов в событии состояния. Проблема в нашей конкретной области-дизайне… Мы смогли отделить и ограничить область применения различных аспектов предметной области/бизнес-логики, чтобы они были автономными, в то время как существует более широкая «техническая сантехника», которая абстрагируется. Это было хорошо, но привело к тому, что мы стали вызывать определенные функции для передачи определенных типов в общие функции сантехники.
2. Я не уверен, имеет ли смысл мой предыдущий комментарий, но, короче говоря… чтобы уменьшить количество повторяющегося кода «сантехники», у нас есть очень простые модули доменной логики (читаемые заинтересованными сторонами, не являющимися разработчиками), которые были сведены к очень простым вещам. Это работает довольно элегантно, но, по сути, нам нужно пройти эти проверки, чтобы заставить его работать. Однако то, что вы предложили, заставляет меня задуматься о том, чтобы найти способы переориентировать » где » на самом деле должна быть написана эта конкретизация. Есть о чем подумать….! Однако я рассмотрю эту переориентацию позже. Спасибо.