2012-05-03 75 views
3

是否有可能做模式匹配的變量,而不是常量:OCaml的模式匹配與非常量

# let x = 2 in 
let y = 5 in 
match 2 with 
| x -> "foo" 
| y -> "bar" 
| _ -> "baz";; 
      let y = 5 in 
Warning 26: unused variable y. 
    let x = 2 in 
Warning 26: unused variable x. 
    | y -> "bar" 
Warning 11: this match case is unused. 
    | _ -> "baz";; 
Warning 11: this match case is unused. 
- : string = "foo" 

顯然,這種語法中,x -> "foo"情況發生的一切。有沒有辦法讓它等同於:

match 2 with 
| 2 -> "foo" 
| 5 -> "bar" 
| _ -> "baz" 

其中匹配表達式的值是在運行時確定的嗎?

回答

5

您需要when後衛:

let x = 2 in 
let y = 5 in 
match 2 with 
| z when z = x -> "foo" 
| z when z = y -> "bar" 
| _ -> "baz";; 

的錯誤消息是非常有啓發性。當您使用:

let x = 2 in 
... 
match 2 with 
| x -> "foo" 
| ... 

新值x陰影值x在以前的時候,讓綁定的第一個錯誤信息。此外,由於新的x匹配所有內容,因此y_的兩個模式顯然是多餘的。

請注意,匹配常數(match 2 with)不是一個好主意。

+0

是啊,我知道,常量匹配是不是一個好主意。這僅僅是爲了舉例。 –

+0

我認爲在這裏使用'when'守衛是一個壞主意,並且往往會在程序員(特別是初學者)中造成不好的風格。 – gasche

3

A「時,」後衛是你在找什麼在這裏:

let x = 2 in 
let y = 5 in 
match 2 with 
| x' when x' = x -> "foo" 
| y' when y' = y -> "baz" 
| _ -> "baz" ;; 

...雖然我不知道爲什麼你會永遠想匹配以恆定的。

+1

與常數匹配僅僅是爲了舉例。 –

6

A when在我看來,守衛是一個壞主意。初學者傾向於過度使用他們覺得方便的模式匹配語法,這會導致他們的應用程序出現微妙的錯誤。對於一個會注意到「嘿,| y -> ..不是我想要的」的人,其他十個人會犯這個錯誤,並且不會直接注意到它。

你應該勸阻這種容易出錯的模式。我對初學者的個人建議是從不使用使用when只使用使用模式匹配來解構歸納數據類型(如列表,樹,選項等)的值。整數模式匹配幾乎總是一個錯誤。

我推薦使用if ... then .. else if .. then .. else來代替。

if z = x then "foo" 
else if z = y then "bar" 
else "baz" 

什麼時候合法使用when?當其他案例確實從模式匹配(測試嵌套模式等)中獲益時,或者在對匹配值進行深層去構造時產生的值執行測試時,有一個是可以理解的。它通常可以通過合併兩個分支並在本地使用if..then..else來轉換。

一個exampe這裏不方便刪除如下(測試相結合,解構):

match foo with 
| (Baz x) when pred x -> ... 
| _ -> ...