2015-04-22 43 views
4

我经常在let语句中进行模式匹配,其中我知道结果的形状。很显然,我不能指望编译器通常会推断这些知识,但也许有一种更简单的方式来做到这一点。警告8:let语句中的模式匹配警告不完整

举个例子,请看下面的代码:

type foo = A of int | B of string 
let x = (true, A 0) 
let (b, A i) = x in i + 2 

哪个正确警告我,说的(_, B _)结果是不匹配的。一种可能的方法是明确处理丢失的案例,如下所示:

let (b,i) = match x with 
    | (a, A j) -> (a,j+2) 
    | _ -> failwith "implementation error!" 

但是,这掩盖了实际的计算。有更简洁的选择吗?

编辑: Jeffrey Scofield表示,在没有嵌套的情况下,显式转换函数效果很好。是否还有嵌套类型匹配的版本?

+2

通常安全的方法是定义'i'然后定义'x',这样你就可以提取'i'而没有运行时错误的风险;例如'让我= 0 ;;让x =(true,A i);; i + 2 ;;' –

回答

4

对于简单情况,您可以编写一个部分函数来提取感兴趣的值,与List.hd类似。

let int_of_foo = function 
    | A i -> i 
    | _ -> raise (Invalid_argument "int_of_foo") 

let string_of_foo = function 
    | B s -> s 
    | _ -> raise (Invalid_argument "string_of_foo") 

let (_, f) = x in int_of_foo f + 2 

也有(非部分)用于投影对功能:

int_of_foo (snd x) + 2 

(我更新了我的使用x来匹配你的,对不起。)

+0

是的,这就是为什么我给出的例子里面嵌套。 –

+0

在这种情况下,我认为这不会让问题变得更糟,因为它很容易完全匹配一对。但总的来说,我在编码中看到了相同的折衷。 –

+0

问题是深层嵌套如此特殊,以至于不能重用函数。不熟悉代码的人需要查看其定义。 –

6

如果你确信你找到合适的案例,并且您使用的是OCaml 4.02或更高版本,您可以将[@@warning "-8"]添加到您的声明中。

有关属性的更多详细信息,请参阅the OCaml manual

在以前的OCaml版本中,您可以禁用整个文件的警告(这取决于您的构建工作流程),还是使用显式模式匹配,如Jeffrey Scofield的答案中所述。

虽然我会建议不要使用“禁用整个文件的警告”,因为它会掩盖其他不完整的模式匹配,这可能会以目前的意外方式破坏您的代码(这很容易发现)...或者某处在未来(例如,如果你在稍后的升级中改变你匹配的类型)。

1

如果您使用多态变体来代替,例如,您经常可以在没有声明的情况下执行此操作(即,在编译时检查您的代码)。

type foo = [`A of int | `B of string] 
let x = (true, `A 0) 
let (b, `A i) = x in i + 2