OCaml: Pattern matching vs If/else statements

18,762

Solution 1

I don't think there's a clear cut answer to that question. First, the obvious case of pattern matching is when you need destructing, e.g.:

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

Another obvious case is when you're defining a recursive function, pattern matching make the edge condition clearer, e.g.:

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

instead of:

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

That might not be a great example, just use your imagination to figure out more complex edge conditions! ;-)

In term of regular (say C like) languages, I could say that you should use pattern matching instead of switch/case and if in place of the ternary operator. For everything else it's kind of a grey zone but pattern matching is usually preferred in the ML family of languages.

Solution 2

As far as I know the signifincant difference is that the expression at the guards in the match statement is a pattern which means you can do things that allow you to break apart the shape (destruct) the matched expression, as Nicolas showed in his answer. The other implication of this is that code like this:

  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;

won't do what you expect. This is because x in the match statement does not refer to the x in the let statement above it but it's a name of the pattern. In cases like these you'd need to use if statements.

Solution 3

For me if..then..else is equivalent to match .. with | true -> .. | false -> .., but there's a syntax sugar if you are facing cases with nested pattern matching, using if..else in an interlace way can help you avoiding to use begin...end to separate different level of patterns

match .. with
| true -> 
    if .. then 
      match .. with
      | true -> ..
      | false -> ..
    else
      ...
| false -> ...

is more compact than

match .. with
| true ->
   begin 
    match .. with
    | true -> 
       begin
         match .. with
         | true -> ..
         | false -> ..
       end
    | false -> 
      ...
   end
| false -> ...
Share:
18,762
Casey Patton
Author by

Casey Patton

I'm a computer science student at UCLA.

Updated on June 05, 2022

Comments

  • Casey Patton
    Casey Patton almost 2 years

    So, I'm totally new to OCaml and am moving pretty slowly in getting my first functions implemented. One thing I'm having trouble understanding is when to use pattern matching abilities like

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

    vs using the if else structure like

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

    When should I use each?

    • Daniel H
      Daniel H almost 11 years
      The accepted answer below seems good in most cases. However, like in most (all?) programming languages, it's rarely a good idea to say something along the lines of if condition then true else false; you can instead just use condition. In this case, you can say let foo a = (a = []) and avoid both pattern matching and if statements.
  • Michael Ekstrand
    Michael Ekstrand over 12 years
    +1. I'd augment this with one more rule of thumb. If you're pattern-matching against true and false, consider an if. If your if uses a function to express a clear pattern-match, consider match. Plus match can avoid function calls, unlike many if expressions.
  • Jeffrey Scofield
    Jeffrey Scofield about 8 years
    FWIW, I don't think match x with 3 -> f x | _ -> g x is going to be any more efficient than if x = 3 then f x else g x. I would personally concentrate on clarity of the code.
  • Neil Philip
    Neil Philip about 8 years
    In that case, I would agree. But consider the case, match x with | 0 -> 1 | 1 -> 2 | 2 -> 3 | _ -> x + 1 vs if x = 0 then 1 else if x = 1 then 2 else if x = 2 then 3 else x + 1. If you were to benchmark these functions, the pattern matching would be significantly more efficient. As the cases increase (especially when accelerated with recursion), the performance differences can increase by orders of magnitude.
  • ELLIOTTCABLE
    ELLIOTTCABLE almost 6 years
    I hate to dispense a downvote on SO, but this is actually incorrect — any destructuring in a let will behave exactly the same as that same destructuring in a match clause. let (hd :: _) = [1; 2; 3]. (In fact, IIRC, let-assignment actually desugars to a pattern-match.)
  • sashang
    sashang almost 6 years
    @ELLIOTTCABLE I think the example I wrote is bad. I meant that something like: match s with x -> .... is not the same as if s = x then . The x in the match statement is always going to pattern match with s. The x in the if statement is testing for equality.