In the last lecture we, defined the factorial function and illustrated the use of pattern matching. In this chapter we elaborate on it a bit more.
We have already seen the list type. There is an algebraic way of defining a list. A list either an empty list or an element attached to the front of an already constructed list. An empty list in Haskell is expressed as []
where as a list whose first element is x
and the rest is xs
is denoted by x:xs
. The notation [1,2,3]
is just a syntactic sugar for 1:(2:(3:[]))
or just 1:2:3:[]
as :
is a right associative operator. We now illustrate pattern matching on list by giving the example of the map
function. The map
function takes a function and a list and applies the function on each element of the list. Here is the complete definition including the type
1 |
|
Since a list can either be empty or of the form (x:xs)
this is a complete definition. Also notice that pattern matching of variables is done here.
Before we proceed further, let us clarify the >
's at the beginning of the of the lines. This is the literate programming convention that Haskell supports. Literate programming is a style of programming championed by Knuth, where comments are given more importance than the code. It is not restricted to Haskell alone; in fact TeX and METAFONT were written first written by Knuth in a literate version Pascal language called WEB and later on ported to CWEB, a literate version of the C Programming language. The ghc
compiler and the ghci
interpreter supports both the literate and non-literate version of Haskell.
Normally any line is treated as part of the program unless the commented. In literate haskell all lines other than
\begin{code}
\end{code}
are treated as comments. We will use this literate style of programming; we will use only the first form i.e. program lines start with a >
. The advantage is that one can download the notes directly and compile and execute them.
We now illustrate the use of wild card patterns. Consider the function that tests whether a list is empty. This can be defined as follows.
1 |
|
The pattern _
(under score) matches any expression just like a variable pattern. However, unlike a variable pattern where the matched value is bound to the variable, a wild card discards the value. This can be used when we do not care about the value in the RHS of the equation.
Besides lists Haskell supports the tuple type. Tuple types corresponds to taking set theoretic products. For example the tuple (1,"Hello")
is an ordered pair consisting of the integer 1
and the string "Hello"
. Its type is (Int,String)
or equivalently (Int,[Char])
as String
is nothing but [Char]
. We illustrate the pattern matching of tuples by giving the definition of the standard functions curry
and uncurry
.
In haskell functions are univariate functions unlike other languages. Multi-parameter functions are captured using the process called currying. A function taking two arguments a
and b
and returning c
can be seen as a function taking the a
and returning a function that takes b
and returning c
. This kind of function is called a curried
function. Another way in which we can represent a function taking 2 arguments is to think of the function as taking a tuple. This is its uncurried form. We now define the higher order functions that transforms between these two forms.
1 |
|
The above code clearly illustrates the power of Haskell when it comes to manipulating functions. Use of higher order functions is one of the features that we will find quite a bit of use.
In this lecture we saw
Pattern matching for lists,
Tuples and pattern matching on them,
Literate haskell
Higher order functions.