In my previous post, I mentioned Lists briefly. I had shown you examples of valid and invalid lists, some enumeration techniques and some operators you can use with lists. But there is so much more we can learn about Lists. We’ve barely scratched the surface. That is why I’ve dedicated this post entirely to Lists.
Hello again, Lists
A List is a collection of elements. The elements of a list can be of any type, as long the elements are of the same type. Let’s have a look how a list look like in a type signature using a simple example with the
A List contains its elements within the square brackets
 separated by commas. So what is
a is type variable, it can be of any type. This means we can even have a list of lists e.g.
[[1,2,3], [2,3,4]]. You can start to imagine how powerful and complex lists can be.
In general when we talk about arrays, arraylists, sets, collections etc, we normally require them to have some basic features and capabilities.
There are 2 ways to add element(s) to a Haskell list. The first way is the cons operator,
: operator only allows you add an element to the front of the list i.e. it becomes the first element. The second way is by the concat operator,
++. This operator takes 2 lists and append them together.
1 2 3 4 5 6 7 8
There are many ways in Haskell we can check whether an element is found in a list. Without introducing too many new terms, the
elem function is probably the simplest way to go. It is more intuitive to use
elem infix, so this is how we can use it: 1
`elem` [1,2,3] will give you
False if otherwise.
Some times we want to get an element at the i th position. For that we have the
!! function. E.g.
[1,2,3] !! 0 will give you
1. As usual, index starts with zero and if you specify an invalid index it will cause an exception.
Because of the behaviour and nature of lists, this is not as straightforward. The way I see it, there are 2 basic ways of deleting elements. The first way is to delete all from the list that matches the requirements. We can
filter for the elements we are interested in.
1 2 3 4 5 6 7
filter is a function that takes a predicate and a list as arguments. You can see its type signature in Line 3 above: The predicate,
(a -> Bool), and the list,
[a]. Finally it returns another list
[a]. The predicate is also a function. It is a function that returns a
filter means: For every element that returns
True from the predicate function, include it in the output list.
The second way is to delete the n th item from the list. I’m guessing this kind of operation is not common in Haskell programming, despite searching for it I wasn’t able to find a neat answer. The intuition of the following method is to first cut the list into 2 parts at the n th item. Then we remove that n th item before joining the 2 parts back together. Let’s look at this example which tries to delete the element
4 from the list.
1 2 3 4 5 6 7
There are several new terms and functions here, so let us go through them one by one.
This assigns the list to
splitAt is a function takes an integer (the position) and a list, and then returns a tuple of 2 lists. This is the cutting function. What is a tuple? It is a data structure that contains multiple parts. I like to see it a ordered group of things. In this example, we have a tuple of 2 elements. You can have, however, as many elements in a tuple as you like. We saw that the outcome of
([1,2,3],[4,5,6,7,8,9,10]) when we split at index 3, which is element
4 in our list.
1 2 3 4 5 6
snd are functions for tuples.
fst is short for first,
snd is short for second. Looking at the type signatures, it is easy to tell what is going for each function.
drop, it is a function that removes a specified number of elements from the beginning of a list. We will talk more about it in the later section of this post.
Line 5 of our example, Deleting 4 from our list, we get the first part of the tuple and join with the second of the tuple, with the 1st element of the second part removed. And there you have it.
Basic Functions on Lists
There are many more basic functions we can apply on lists.
1 2 3 4
This should be straightforward enough.
1 2 3 4
So far so good.
1 2 3 4
Well, need no explanation.
head, tail, init, last
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
last are some of the most commonly used functions for lists. However, sometimes, they also considered unsafe. Yup, they don’t work with empty lists. This exception cannot be caught during compile time, so be mindful whether you are dealing with empty lists.
I really like the illustration from Learn You A Haskell For Great Good. It is the best I’ve seen, and it really helped me understand these functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
drop are functions that returns sub-lists from lists. Unlike the previous 4 functions, they are more safe and do not cause exceptions when applied on empty lists. If you look at their type signatures, you can see that both of them take an
Int and a list and returns a list. The
Int, integer, is simply the number of elements you wish to take/drop.
To be continued…
Okay, we have gone through the fundamentals and numerous basic functions for Lists. But we are not done yet. There are many more advanced functions like
foldr that can be applied to lists. However due their complexity, I’ll have to leave them for the next post!
List Monster from Learn You A Haskell For Great Good