OCaml list match pattern
Asked Answered
T

2

6

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.

Tillett answered 20/2, 2016 at 3:13 Comment(1)
Ocaml will give you a very explicit warning if it thinks the patterns do not cover all cases.Phony
M
5

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.

Marxist answered 20/2, 2016 at 5:15 Comment(3)
thanks, so it is always best to match cases with few elements first?Tillett
no. in this case, different orders yield same code.Marxist
Technically, the syntax [h1; h2; h3; _] is valid, it just matches a list of four elements instead of what @Tillett wants.Faulk
B
0

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
Brevet answered 17/5, 2023 at 23:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.