Search code examples
f#discriminated-unionqualified-name

Can one set default values for Discriminated Union types?


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


Solution

  • 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).