2012-01-30 66 views
5

這是我書中的代碼片段,我不確定匹配是如何工作的,因爲它似乎是第一個匹配所有內容的案例。以下是Ocaml向我發出的警告:爲什麼OCaml模式「zero - > zero」似乎匹配所有內容?

# let zero = 0;; 
# let one = 1;; 
# let rec fib i = 
match i with 
zero -> zero 
| one -> one 
| j -> fib (j - 2) + fib (j - 1);; 
Characters 57-60: 


Warning: this match case is unused. 
Characters 74-75: 
Warning: this match case is unused. 
| one -> one 
^^^ 
| j -> fib (j - 2) + fib (j - 1);; 
^ 
val fib : int -> int = <fun> 
# fib 1;; 
- : int = 1 
# fib 2002;; 
- : int = 2002 

回答

9

這是一個相當常見的混淆來源。實質上,您希望將模式從常量(如01)以及綁定的標識符構建爲模式。

當一個標識符出現在一個模式中時,它匹配任何東西,並將匹配的值綁定到標識符。模式中的標識符而不是是指與標識符相關聯的任何先前值。所以,事實上,您的模式將始終與第一種情況匹配,並將zero綁定爲值i

您可以想象,您希望能夠爲常量值賦予名稱,然後在模式中使用名稱而不是常量。然而,OCaml(與其他FP語言一樣)不以那種方式工作。一個好處(在我看來)是它保持簡單。

+1

結果您可以使用常量忽略,如果你做一些像'x where x == zero'(精確的語法雖然逃過了我) – hugomg 2012-01-30 03:17:07

+2

你可以使用'when'來爲一個匹配添加額外的測試,但它不會改變模式的含義。一個額外的測試,如果你的模式只是一個標識符,這只是另一種編寫'if'語句的方法(if語句沒什麼問題,你可能用它來測試命名常量) – 2012-01-30 03:23:00

+0

你傑弗裏,我發現這很漂亮見地。 – 2012-01-30 04:38:31

0

我以爲我會補充一點,如果你重寫了代碼如下,這將很好地工作:

# let zero = 0;; 
# let one = 1;; 
# let rec fib i = 
match i with 
    0 -> zero 
| 1 -> one 
| j -> fib (j - 2) + fib (j - 1);; 

的根本問題(如相當好於對方的回答解釋)是您可以使用與全局變量相同的名稱創建新的本地變量,並且使用匹配左側的任何變量名稱只會創建一個新名稱的局部變量,並用任何匹配的名稱填充它。正如j是一個新的局部變量,它包含任何正在匹配的內容,zero也是如此。並且它是在更大範圍內先前聲明的事實被ocaml的(這就是爲什麼你可以愉快地寫東西像

let x = 1;; 
let x = 2 in let x = 3 in x;; 

它給出了3

+0

這是一個好點;模式中'zero'的外觀會創建一個嵌套作用域,其中'zero'根據匹配被綁定到一個新值。大多數編程語言都支持嵌套的作用域,而不僅僅是OCaml。替代品通常更糟;您可能不想限制本地名稱的選擇,具體取決於代碼中其他位置使用的名稱。 – 2012-02-01 07:05:00