In functional programming, we are "more concerned with how something is defined
than with the specifics of how it is calculated" (take this motto with a grain of salt,
however, efficiency still matters in some cases). The idea is that it is a compiler or
interpreter's job to figure out how to reach a solution, not the programmer's.
One useful way of specifying how a function is defined is to describe what results it will
return given different types of inputs. A powerful way of describing "different types of
inputs" in Haskell is using pattern matching. We can provide multiple definitions of a
function, each having a particular pattern for input arguments. The first listed definition
that succeeds in matching a given function call is the one used for that call. In this
that succeeds in matching a given function call is the one used for that call. In this
manner, you can pull out the head and tail of a list, match specific input values, identify
empty lists as arguments (for recursion usually), and analyze other patterns. You
cannot, however, perform value comparisons with pattern matching (e.g., "n