为什么以下代码会给我一个不完整的模式匹配警告和运行时异常。
type Left =
| L1 of int
| L2 of int
type Right =
| R1 of int
| R2 of int
type Directions =
| LeftDir of Left
| RightDir of Right
let unpack (LeftDir (L1 i)) = i
let x = unpack (LeftDir (L1 10))
let y = unpack (LeftDir (L2 20))
显然答案是因为IT是一个不完整的模式匹配;-)
但是为什么F#不够聪明(或F#语言规范的编写者)知道unpack
只需要LeftDir containing a L1
?为什么需要完整的模式匹配?
答案 0 :(得分:5)
从概念上讲,LeftDir
和L1
不是类型(尽管它们在IL级别上以这种方式实现);相反, Directions
是一种类型,LeftDir
只是该类型的一个构造函数,同样适用于Left
和L1
。如果这不是立即有意义的话,请重新考虑代数和类型的概念。
由于F#函数参数是严格基于类型的(与其他语言不同),unpack
必须采用类型为Directions
的对象,以及该对象实例是否是通过LeftDir
构建的必须在运行时确定RightDir
;如果通过LeftDir
,同样也可以通过Left
或L1
来构建其包含的L2
实例。
完全模式匹配不严格必要,但鉴于强大的,静态类型语言(如F#)的核心目标是在编译时捕获尽可能多的错误,警告建议完成模式匹配,以避免运行时错误。
答案 1 :(得分:2)
以一种只处理两种可能情况之一的方式显式定义一个函数,然后当你没有处理第二种情况时,你会感到惊讶。
您认为应该怎么做?
受歧视的工会的全部意义是拥有一个已知数量的“子类型”的封闭类型,您可以用详尽的方式处理。
您可以编写一个仅关注特定情况的函数,例如LeftDir (L1 x)
,但该函数仍需要能够处理其他情况。您可以自己提供处理,也可以以不完整匹配例外的形式免费获取
答案 2 :(得分:1)
问题在于,无法在编译时指定unpack
采用Directions
的特定实例。唯一的可能性是运行时检查,因此您会收到编译器警告。