参数的不完全模式匹配

时间:2015-01-12 21:12:05

标签: f# pattern-matching

为什么以下代码会给我一个不完整的模式匹配警告和运行时异常。

 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?为什么需要完整的模式匹配?

3 个答案:

答案 0 :(得分:5)

从概念上讲,LeftDirL1不是类型(尽管它们在IL级别上以这种方式实现);相反, Directions 是一种类型,LeftDir只是该类型的一个构造函数,同样适用于LeftL1。如果这不是立即有意义的话,请重新考虑代数和类型的概念。

由于F#函数参数是严格基于类型的(与其他语言不同),unpack必须采用类型为Directions的对象,以及该对象实例是否是通过LeftDir构建的必须在运行时确定RightDir;如果通过LeftDir,同样也可以通过LeftL1来构建其包含的L2实例。

完全模式匹配严格必要,但鉴于强大的,静态类型语言(如F#)的核心目标是在编译时捕获尽可能多的错误,警告建议完成模式匹配,以避免运行时错误。

答案 1 :(得分:2)

以一种只处理两种可能情况之一的方式显式定义一个函数,然后当你没有处理第二种情况时,你会感到惊讶。

您认为应该怎么做?

受歧视的工会的全部意​​义是拥有一个已知数量的“子类型”的封闭类型,您可以用详尽的方式处理。

您可以编写一个仅关注特定情况的函数,例如LeftDir (L1 x),但该函数仍需要能够处理其他情况。您可以自己提供处理,也可以以不完整匹配例外的形式免费获取

答案 2 :(得分:1)

问题在于,无法在编译时指定unpack采用Directions的特定实例。唯一的可能性是运行时检查,因此您会收到编译器警告。