F# 可以为有区别的联合类型设置默认值吗?
我实现了一个用于选择函数的有区别的联合类型:F# 可以为有区别的联合类型设置默认值吗?,f#,discriminated-union,qualified-name,F#,Discriminated Union,Qualified Name,我实现了一个用于选择函数的有区别的联合类型: type BooleanCombinator = | All | Some | None | AtLeast of int | MoreThan of int | NotMoreThan of int | LessThan of int | ExactlyOne | ExactlyTwo | AllButOne | AllButTwo let boolToInt
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
类型布尔组合器=
|全部
|一些
|没有
|至少是整数
|超过整数
|不超过整数
|莱斯特尚国际酒店
|精确的
|正好两个
|烯丁酮
|奥尔布托
设boolToInt(b:bool):int=如果是b,则为1,否则为0
let combineBooleans(组合子:布尔组合子)
(布尔:布尔列表)
:bool=
设n=List.sumBy boolToInt bools
匹配组合符
|BooleanCombinator.All->List.forall id bools
|BooleanCombinator.Some->bools |>List.id
|BooleanCombinator.None->bools |>List.exists id |>not
|BooleanCombinator.AtLeast i->n>=i
|BooleanCombinator.MoreThan i->n>i
|布尔组合符.不超过i->nn=1
|BooleanCombinator.ExactlyTwo->n=2
|BooleanCombinator.AllButOne->n=bools.Length-1
|BooleanCombinator.AllButTwo->n=bools.Length-2
在我看来,这是正常的,但编译器开始将Some
和None
的所有实例视为属于此DU,而不是选项
DU
我不想用选项替换部分
。用选项替换部分
和无
。无
有没有办法告诉编译器,不合格的部分
和无
实际上是选项。部分
和选项。无
或者我应该给这些DU案例赋予不同的名称,比如
AtLeastOne
和ExactlyZero
在F#中解决名称冲突的一般规则是“最后声明获胜”。由于自定义DU是在选项
之后声明的,因此它的构造函数部分
和无
胜过选项
的构造函数
但此规则提供了一种解决问题的方法:您只需在自定义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
被推断为分别具有类型Bogus->int
和Bogus
,因为它们体内的一些
和无
指的是伪。一些
和伪.无
函数f
和值y
被推断为具有选项
相关类型,因为它们体内的Some
和None
指的是Some
函数和我刚才定义的(| Some | None |)活动模式
当然,这是一种相当老套的恢复现状的方法。这将使编译器信服,但人类仍然很难阅读您的代码。我建议您改名DU的案例。您可以使用[]
属性标记DU
这意味着,无论何时在代码中使用案例名称,您都需要使用类型限定案例名称,这是您现在在match
表达式中所做的事情
这样一来,一个不合格的Some
仍将被解析为选项。Some
,尽管您重新使用了该名称
这是一种很有用的技巧,可以知道什么时候你想为DU案例使用一个简洁的名称,比如None
,Yes
,Failure
等等,这本身就可能让读者(或编译器)感到模棱两可或困惑。这实际上比我的答案要好。我完全忘记了RequireQualifiedAccess
。
> g
g : Bogus -> int
> f
f : 'a option -> int
> x
Bogus
> y
int option