2012-01-30 20 views
5

Dưới đây là một đoạn mã từ cuốn sách của tôi, và tôi không chắc chắn về cách các công trình phù hợp rõ ràng vì có vẻ như trường hợp đầu tiên khớp với mọi thứ. Dưới đây là các cảnh báo mà Ocaml ném cho tôi:Tại sao mẫu OCaml `zero -> zero` dường như phù hợp với mọi thứ?

# 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 

Trả lời

9

Đây là một nguồn gây nhầm lẫn khá phổ biến. Về bản chất, bạn muốn nghĩ đến các mẫu được xây dựng từ các hằng số (như 01) và các mã định danh là bị ràng buộc theo mẫu.

Khi số nhận dạng hiển thị trong mẫu, nó khớp với bất kỳ thứ gì và liên kết giá trị khớp với số nhận dạng. Số nhận dạng trong một mẫu không không đề cập đến bất kỳ giá trị nào trước đó được liên kết với số nhận dạng. Vì vậy, trên thực tế, mẫu của bạn sẽ luôn khớp với trường hợp đầu tiên và liên kết zero với giá trị là i.

Bạn có thể tưởng tượng rằng bạn muốn có thể đặt tên cho các giá trị không đổi, sau đó sử dụng các tên thay vì các hằng số trong một mẫu. Tuy nhiên OCaml (giống như các ngôn ngữ FP khác) không hoạt động theo cách đó. Một lợi thế (dường như với tôi) là nó giữ mọi thứ đơn giản.

+1

Bạn có thể sử dụng hằng nếu bạn làm một cái gì đó như 'x nơi x == zero' (cú pháp chính xác thoát tôi mặc dù) – hugomg

+2

Bạn có thể sử dụng' khi' để thêm một thử nghiệm bổ sung cho một trận đấu, nhưng nó không thay đổi ý nghĩa của mẫu. Nếu mẫu của bạn chỉ là một định danh, thì đây chỉ là một cách khác để viết một câu lệnh 'if' (không có gì sai với câu lệnh' if', đó là những gì bạn có thể sử dụng để kiểm tra các hằng số được đặt tên.) –

+0

Cảm ơn bạn Jeffrey, tôi thấy điều này khá sâu sắc. –

0

tôi nghĩ rằng tôi muốn thêm rằng nếu bạn viết lại mã để như sau, rằng nó sẽ hoạt động tốt:

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

Các vấn đề cơ bản (như là khá tốt giải thích trong câu trả lời khác) là bạn có thể tạo các biến cục bộ mới có cùng tên với các biến toàn cầu và sử dụng bất kỳ tên biến nào ở bên trái của trận đấu vừa tạo ra một biến cục bộ mới của tên đó và điền vào nó với bất kỳ thứ gì được khớp. Giống như j là một biến địa phương mới chứa bất kỳ thứ gì đang được so khớp, như vậy là zero. Và thực tế là trước đây nó được tuyên bố trong một phạm vi lớn hơn là bỏ qua bởi Ocaml (đó là lý do tại sao bạn hạnh phúc có thể viết những thứ như

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

mà đưa ra một kết quả của 3.

+0

Đây là một điểm tốt; sự xuất hiện của 'zero' trong mẫu tạo ra một phạm vi lồng nhau trong đó' zero' bị ràng buộc với một giá trị mới dựa trên kết quả khớp. Hầu hết các ngôn ngữ lập trình đều hỗ trợ các phạm vi lồng nhau, không chỉ OCaml. Các lựa chọn thay thế thường tồi tệ hơn; bạn có thể không muốn giới hạn các lựa chọn cho tên địa phương tùy thuộc vào tên được sử dụng ở nơi khác trong mã. –