This corresponds to section 3.3 in Ullman. This chapter is very important, and the information may not be intuitive.
The parameter list for a function can also be a list of patterns, and there is an extended syntax to support patterns. The syntax is:
fun identifier (pattern1) = expression1
| identifier (pattern2) = expression2
| identifier (pattern3) = expression3
...
Example:
> fun reverse( nil ) = nil
= | reverse( x::xs ) = reverse( xs ) @ [ x ];
val reverse = fn : 'a list -> 'a list
When this function is called with the argument ``nil'', the first
pattern is matched, and the function returns ``nil''. When the
function is called with a list, the list is split into its head and
tail in order to match and bind to the pattern ``x::xs''. The
parameters ``x'' and ``xs'' are then used to create the
return value.
It is possible to use patterns to match tuples, lists, scalars, and user-defined types (this provides ML with much of its powers of data abstraction).
Be sure your patterns go from most specific to least specific from the top down, and that a higher-up pattern won't possibly match a lower pattern.