代码之家  ›  专栏  ›  技术社区  ›  Soldalma

可以为区分的联合类型设置默认值吗?

  •  3
  • Soldalma  · 技术社区  · 6 年前

    我实现了一个用于选择函数的区分联合类型:

    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
    

    在我看来这看起来不错,但是编译器开始查看 Some None 属于这个杜,而不是 Option 杜。

    我不想把我所有的代码都替换掉 一些 具有 Option.Some 具有 Option.None 是的。

    有没有办法告诉编译器 一些 实际上 选择。一些 选项。无 是吗?

    或者我应该给这些du案件起不同的名字,比如 AtLeastOne ExactlyZero

    2 回复  |  直到 6 年前
        1
  •  3
  •   scrwtp    6 年前

    你可以用 [<RequireQualifiedAccess>] 属性。

    这意味着无论何时在代码中使用案例名称时,都需要将其与类型限定在一起—这是您现在在 match 表达。

    这样就不合格了 Some 仍然会下定决心 Option.Some ,尽管你重复使用了这个名字。

    这是一种有用的技巧,可以知道何时要对du case-like使用一个时髦的名称 None 我是说, Yes 我是说, Failure 对读者(或编译器)来说,这本身就是模棱两可或令人困惑的。

        2
  •  6
  •   Fyodor Soikin    6 年前

    在f中解决名称冲突的一般规则是“最后一个声明获胜”。因为你的自定义du是在 Option ,它的构造函数 Some None 战胜那些 选择权 是的。

    但这条规则提供了一种解决问题的方法:只需在自定义du之后“重新插入”声明:

    type Bogus = Some of int | None
    
    let g = function Some _ -> 42 | None -> 5
    let x = Some 42
    
    let inline Some a = Option.Some a
    let inline None<'a> = Option.None : 'a option
    let (|Some|None|) = function | Option.Some a -> Some a | Option.None -> None
    
    let f = function Some _ -> 42 | None -> 5
    let y = Some 42
    

    如果你检查 g 我是说, x 我是说, f ,和 y 在上述代码中:

    > g
    g : Bogus -> int
    
    > f
    f : 'a option -> int
    
    > x
    Bogus
    
    > y
    int option
    

    功能 和价值 X 被推断为具有类型 Bogus -> int Bogus 分别是因为 一些 在他们的身体里 Bogus.Some Bogus.None 是的。

    功能 f 和价值 是的 据推测 选择权 -相关类型,因为 一些 在他们的身体里是指 一些 函数和 (|Some|None|) 我刚才定义的活动模式。

    当然,这是一种相当老套的恢复现状的方法。这将使编译器信服,但人类仍然很难阅读您的代码。我建议你改名为du。