Reputation: 161
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
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
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