2009-01-07 36 views
1

我想強化一種模式,以便僅匹配通過附加驗證功能的數字。你可以嵌套一個「雙重缺點」模式匹配?

let (|IsValid|_|) n = ... 

let (|Nil|One|Two|) (l : int list) = 
    match l with 
    | a :: b :: t -> Two(a + b) 
    | a :: t  -> One(a) 
    | _   -> Nil 

'一' 的情況下很容易:

| IsValid(a) :: t -> One(a) 

'兩化' 情況並不明顯,我。它需要驗證數字的總和。我可以在不使用防護裝置的情況下做到這一點嗎?

...

編輯:我可以使用,當後衛(用布爾返流的isValid函數)是這樣的:

| a :: b :: t when isValid a + b -> Two(a + b) 

這不僅僅是模式匹配的那麼優雅;更糟的是,a + b應用了兩次。另外請注意,這是我的實際代碼的簡化版本(我並不是試圖簡單地匹配不同長度的列表,例如) - 問題是關於雙重缺陷模式的嵌套匹配。

+0

我怕我不不知道你在問什麼,也不知道你想如何驗證你的號碼。如果你提供了一個樣本輸入和一個預期的輸出,這將有所幫助。 – Juliet 2009-01-07 16:00:12

+0

向我們展示您對「何時」條款的看法,然後我們可以告訴您更好的答案。 – nlucaroni 2009-01-07 21:55:03

回答

2

我的解決方法:添加一個「助手」識別器與設計在父模式中使用的返回值:

let (|MatchTwo|_|) = function 
    | a :: b :: t -> Some(a + b :: t) 
    | _ -> None 

使用它,像這樣:

let (|Nil|One|Two|) (l : int list) = 
    match l with 
    | MatchTwo(IsValid(a) :: t) -> Two(a) 
    |   IsValid(a) :: t -> One(a) 
    | _       -> Nil 
2

當你這樣做:

| a :: b :: t -> ... 

你不一定匹配列表中的兩個元素。最好使用[]而不是t來精確匹配兩個元素 - t可以是更多元素的列表。

| a :: b :: [] -> Two (a+b) 

這將確保您匹配兩個且只有兩個元素 - 免費檢查錯誤!即使您期望函數只接受0,1或2個元素的列表,我仍然建議您這樣做。所以,

編輯:

let (|MatchTwo|_|) = function 
    | a :: b :: t -> Some(a + b :: t) 
    | _ -> None 
let (|Nil|One|Two|) (l : int list) = match l with 
    | MatchTwo(IsValid(a) :: t) -> Two(a) 
    | IsValid(a) :: t -> One(a) 
    | _ -> Nil 

呀,使用when。這是一團糟。模式匹配就是這樣,在比賽中應用功能確實沒有意義。但要考慮到我之前提到過的內容。根據您的例子:

match l with 
| a :: b :: t when isValid (a+b) -> Two (a+b) 
| a :: t when isValid (a) -> One a 
| _ -> Nil 

第二個模式會匹配長度的名單不再那麼一個如果的isValid是--be警告第一圖案假的。如果你的意思是匹配一個元素,儘可能在你的模式中具體使用,就這樣做。

如果無論您將a和b(在本例中爲+)中使用的操作的計算成本高昂,那麼在測試isValid並返回變體類型之前,您必須刪除when並使用let語句。