I implemented a Discriminated Union type that would be used to select a function:
type BooleanCombinator =
| All
| Some
| None
| AtLeast of int
| MoreThan of int
| NotMoreThan of int
| LessThan of int
| ExactlyOne
| ExactlyTwo
| AllButOne
| AllButTwo
let boolToInt (b: bool) : int = if b then 1 else 0
let combineBooleans (combinator : BooleanCombinator)
(bools : bool list)
: bool =
let n = List.sumBy boolToInt bools
match combinator with
| BooleanCombinator.All -> List.forall id bools
| BooleanCombinator.Some -> bools |> List.exists id
| BooleanCombinator.None -> bools |> List.exists id |> not
| BooleanCombinator.AtLeast i -> n >= i
| BooleanCombinator.MoreThan i -> n > i
| BooleanCombinator.NotMoreThan i -> n <= i
| BooleanCombinator.LessThan i -> n < i
| BooleanCombinator.ExactlyOne -> n = 1
| BooleanCombinator.ExactlyTwo -> n = 2
| BooleanCombinator.AllButOne -> n = bools.Length - 1
| BooleanCombinator.AllButTwo -> n = bools.Length - 2
This looked Ok to me but the compiler started to look at all instances of Some
and None
as belonging to this DU, instead of the Option
DU.
I do not want to go through all of my code replacing Some
with Option.Some
and None
with Option.None
.
Is there a way to tell the compiler that unqualified Some
and None
are actually Option.Some
and Option.None
?
Or should I just give different names to these DU cases, like AtLeastOne
and ExactlyZero
You can mark your DU with [<RequireQualifiedAccess>]
attribute.
This means that you will be required to qualify the case name with the type whenever you use it in the code - which is something you do now anyway in your match
expression.
That way an unqualified Some
would still be resolved to mean Option.Some
, despite the fact that you reuse the name.
It's a useful technique to know when you want to use a snappy name for a DU case - like None
, Yes
, Failure
etc. - that by itself would be ambiguous or confusing to the reader (or the compiler, for that matter).