We can nest patterns as deep as we like. Anywhere we put a variable in our pattern, we can put another pattern.
exception BadTriple
fun zip3 list_triple =
case list_triple of
([], [], []) => []
| (hd1::tl1, hd2::tl2, hd3::tl3) => (hd1, hd2, hd3)::zip3(tl1, tl2, tl3)
| _ => raise BadTriple
fun unzip3 lst =
case lst of
[] => ([], [], [])
| (a, b, c)::tl =>
let val (l1, l2, l3) = unzip3 tl
in (a::l1, b::l2, c::l3)
end
fun is_sorted intlist =
case intlist of
[] => true
| _::[] => true
| head::(neck::rest) => (head <= neck andalso nondecreasing (neck::rest))
a::(b::(c::d)) (* Match lists with 4 or more elements *)
a::(b::(c::[])) (* Match lists with exactly 3 elements *)
(a, b, c)::d (* Match a list of triplets. *)
Note that _ is a wildcard: It matches anything, but does not bind it to anything.
If you ever have a nested case, consider if nested patterns will work instead.