Oxtis
Oxtis

Reputation: 161

OCaml list match pattern

So I'm writing a simple method that sums up the first 3 or less ints in a list but i'm confused about the match patterns.
I currently have

let sums l = match l with
    | [] -> 0
    | (h1::h2::h3::_) -> h1+h2+h3
    | [h1;h2;h3] -> h1+h2+h3
    | [h1;h2] -> h1+h2
    | [h1] -> h1

Does this cover all the cases? also how come for 3 or more elements I cant write something like [h1;h2;h3;_]?
Sorry if these question seem too simple, I just started learning OCaml and I cant find anything like this online.

Upvotes: 6

Views: 5872

Answers (2)

Chris
Chris

Reputation: 36536

For summing the first three elements of a list, your approach seems quite reasonable. Now imagine you're asked to sum the first five. What about the first twenty?

Yes, you do cover all of the cases, but it's possible to think of this in terms of just two cases using recursion.

We know that if we want to sum the first zero elements of any list, we'll get 0. Likewise, if we want to sum the first n numbers in an empty list, we'll get 0. So the only time that doesn't yield 0 is a non-empty list when n is greater than zero.

In that case we add the first element to summing n - 1 elements of the tail of the list. Applying the function recursively to the tail and decrementing n will converge our function on the base case which returns 0.

# let rec sum_first_n n lst =
    match lst with
    | x::xs when n > 0 -> x + sum_first_n (n - 1) xs
    | _ -> 0;;
val sum_first_n : int -> int list -> int = <fun>
# sum_first_n 3 [7; 8; 9; 10];;
- : int = 24
sum_first_n 3 [7; 8; 9; 10]
7 + sum_first_n 2 [8; 9; 10]
7 + 8 + sum_first_n 1 [9; 10]
7 + 8 + 9 + sum_first_n 0 [10]
7 + 8 + 9 + 0
24

We could also use sequences (since OCaml 4.07) to take the first n elements and then fold + over them.

# let sum_first_n n lst =
    lst 
    |> List.to_seq
    |> Seq.take n
    |> Seq.fold_left (+) 0;;
val sum_first_n : int -> int list -> int = <fun>
# sum_first_n 3 [7;8;9;10];;
- : int = 24

Upvotes: 0

objmagic
objmagic

Reputation: 1028

Does this cover all the cases?

Yes, they cover all the cases, but I would write:

let sums l = match l with
  | [] -> 0
  | [h1] -> h1      
  | [h1; h2] -> h1+h2
  | h1 :: h2 :: h3 :: _ -> h1+h2+h3

Your [h1; h2; h3] is redundant since h1 :: h2 :: h3 :: _ matches it (with wildcard being [])

also how come for 3 or more elements I cant write something like [h1;h2;h3;_]?

well, you just can't. This syntax is not valid.
Edit: sorry I went crazy. This syntax is valid but it matches a list of four elements without binding the last element, which is not something you want.

Upvotes: 5

Related Questions