2015-04-22 63 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