简体   繁体   中英

F# - Cleanest way to Extract/Unwrap an Expected Case's Typed Value from Discriminated Union?

The overall type structure and utilization in my current F# is working very well. However, I want to get some perspective if I am doing something incorrectly or following some kind of anti-pattern. I do find myself very often essentially expecting a particular type in particular logic that is pulling from a more general type that is a Discriminated Union unifying a bunch of distinct types that all follow layers of common processing.

Essentially I need particular versions of this function:

'GeneralDiscriminatedUnionType -> 'SpecificCaseType

I find myself repeating many statements like the following:

let checkPromptUpdated (PromptUpdated prompt) = prompt

This is the simplest way that I've found to this; however, every one of these has a valid compiler warning that makes sense that there could be a problem if the function is called with a different type than the expected. This is fair, but I so far have like 40 to 50 of these.

So I started trying the following out, which is actually better, because it would raise a valid exception with incorrect usage (both are the same):

let checkPromptUpdated input  = match input with | PromptUpdated prompt -> prompt | _ -> invalidOp "Expecting Prompt"    
let checkPromptUpdated = function | PromptUpdated prompt -> prompt | _ -> invalidOp "Expecting Prompt"

However, this looks a lot messier and I'm trying to find out if anyone has any suggestions prior to me doing this messiness all over.

Is there some way to apply this wider logic to a more general function that could then allow me to write this 50 to 100x in a cleaner and more direct and readable way?

This question is just a matter of trying to write cleaner code.

This is an example of a DU that I'm trying to write functions for to be able to pull the particular typed values from the cases:

type StateEvent = 
| PromptUpdated of Prompt
| CorrectAnswerUpdated of CorrectAnswer
| DifficultyUpdated of Difficulty
| TagsUpdated of Tag list
| NotesUpdated of Notes
| AuthorUpdated of Author

If the checkPromptUpdated function only works on events that are of the PromptUpdated case, then I think the best design is that the function should be taking just a value of type Prompt (instead of a value of type StateEvent ) as an argument:

let checkPromptUpdated prompt = 
  // do whatever checks you need using 'prompt'

Of course, this means that the pattern matching will get moved from this function to a function that calls it - or further - to a place where you actually receive StateEvent and need to handle all the other cases too. But that is exactly what you want - once you pattern match on the event, you can work with the more specific types like Prompt .

This works for me

let (TypeUWantToExtractFrom unwrappedValue) = wrappedValue

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM