问题
I've been aware of the F# Choice type for a while , but can't think of any place I'd use it rather than defining my own union type with meaningful named cases.
The MSDN documentation doesn't offer much advice ("Helper types for active patterns with two choices.") and doesn't have any example usages.
I must be missing something - what are the key advantages of this type over a custom union?
回答1:
In my opinion the use cases for the Choice
type are quite similar to the use cases for tuple types. In either case, you will often want to define your own more specific type which is isomorphic to the type (a custom DU for choices; a custom record type for tuples). Nonetheless, over limited scopes or in very generic situations (where good naming may become difficult), it's nice to have anonymous variants.
回答2:
Sure, a more specific union type might be nice for a particular situation, but having a general Choice union means that your code can mesh well with other code when using general constructs such as Workflows, Functors, etc.
IIRC there's not an implementation of the Either Monad (Workflow in F# lingo) in the standard FSharp Core library, but there is one in the FSharpx library (though I couldn't find a constructor for it so I had to roll my own thanks to @MauricioScheffer for poiting me to choose
).
From my limited, mostly C# interop, F# experience, Choice and Option aren't baked into F#'s standard methods as much as Haskell's Maybe and Either algebraic data types are baked into its standard libraries, so you don't get as much of a "this is useful" sense when using them in F# as you might in Haskell, but they are quite useful.
As for an example: in an application I recently wrote I returned Choice1Of2 from methods when I had a successful result and Choice2Of2 with an error message when something went wrong -- whether an exception being caught or a precondition not being met -- and ran my code in a Workflow for flow control. This is one standard use of this union type.
回答3:
Best example is Async.Catch
where you either return a result or an exception, both of which are meaningful.
Having said that, the use of Choice
is relatively limited in F# code and most of the time people use a DU. However, a Choice
might be used when you can't be bothered to define a DU.
Choice
may also have better behavior when interacting with C#
回答4:
I have observed it's value when attempting to enforce the creation of a discriminated union value via a dedicated function and Active Patterns.
Here's the example that was posted:
module File1 =
type EmailAddress =
private
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
// Exposed patterns go here
let (|Valid|Invalid|) (input : EmailAddress) : Choice<string, string> =
match input with
|Valid str -> Valid str
|Invalid str -> Valid str
module File2 =
open File1
let validEmail = Valid "" // Compiler error
let isValid = createEmailAddress "" // works
let result = // also works
match isValid with
| Valid x -> true
| _ -> false
来源:https://stackoverflow.com/questions/16711933/use-case-for-f-choice-type