2011-09-24 135 views
12

所以,我完全是OCaml的新手,並且在實現我的第一個功能方面進展緩慢。我無法理解的一件事是什麼時候使用模式匹配能力像OCaml:模式匹配與If/else語句

let foo = 
[] -> true 
| _ -> false;; 

VS使用的if else結構像

let foo a = 
if a = [] then true else false;; 

什麼時候應該使用的呢?

+1

以下接受的答案在大多數情況下似乎很好。然而,就像在大多數(所有)編程語言中一樣,按照'if condition then true else false'的語句說出一些東西並不是一個好主意。你可以改爲使用'condition'。在這種情況下,你可以說'let foo a =(a = [])'並且避免模式匹配和if語句。 –

回答

15

我不認爲這個問題有明確的答案。首先,模式匹配的情況下,很明顯是當你需要破壞,如:當你定義一個遞歸函數,模式匹配使邊緣更清晰的條件下,例如

let rec sum = function 
    | [] -> 0 
    | head :: tail -> head + sum tail;; 

另一個明顯的例子是:

let rec factorial = function 
    | 0 -> 1 
    | n -> n * factorial(n - 1);; 

代替:

let rec factorial = function n -> 
    if n = 0 then 
    1 
    else 
    n * factorial(n-1);; 

這可能不是一個很好的例子,只是用你的想象力,想出更復雜的邊界條件! ;-)

就定期(比如C類)語言而言,我可以說你應該使用模式匹配而不是switch/caseif來代替三元運算符。對於其他所有內容,它都是灰色區域,但在ML系列語言中通常首選模式匹配。

+0

+1。我會用更多的經驗法則來擴充這一點。如果你對'true'和'false'進行模式匹配,考慮一下'if'。如果你的'if'使用函數來表達一個明確的模式匹配,可以考慮'match'。加上'match'可以避免函數調用,與許多'if'表達式不同。 –

+0

這是一個好點! –

2

據我所知,重要的區別在於,匹配語句中的警衛表達是pattern,這意味着您可以做一些事情,讓您將形狀拆分(破壞)匹配表達式,就像Nicolas顯示的那樣在他的回答中。這樣做的另一個含義是這樣的代碼:

let s = 1 in 
    let x = 2 in 
    match s with 
    x -> Printf.printf "x does not equal s!!\n" x 
    | _ -> Printf.printf "x = %d\n" x; 

不會做你期望的。這是因爲匹配語句中的x在它上面的let語句中沒有引用x,但它是模式的名稱。在這些情況下,您需要使用if語句。

0

模式匹配允許解構複合數據類型,並且通常能夠匹配給定數據結構中的模式,而不是使用if .. then結構等條件。模式匹配也可用於使用| x((r == n))類型構造時的布爾相等案例。我還應該添加模式匹配比if ... then .. constructs更有效率,所以可以自由使用它!

+0

FWIW,我不認爲'與x匹配3 - > f x | _ - > g x'將比'if x = 3 then f x else g x'更有效。我會親自關注代碼的清晰度。 –

+0

在這種情況下,我同意。但考慮一下, '用x匹配| 0 - > 1 | 1 - > 2 | 2 - > 3 |如果x = 0,那麼1,否則如果x = 1,則2,否則,如果x = 2,則3,否則x + 1。如果您要對這些函數進行基準測試,則模式匹配將顯着更高效。隨着案例的增加(特別是在遞歸加速的情況下),性能差異會增加數量級。 –