Learn You a Haskell for Great Good! - Miran Lipovaca [5]
Lists are surrounded by square brackets, and the list values are separated by commas:
ghci> let lostNumbers = [4,8,15,16,23,42]
ghci> lostNumbers
[4,8,15,16,23,42]
Note
Use the let keyword to define a name in GHCi. Entering let a = 1 in GHCi is equivalent to writing a = 1 in a script, then loading it with :l.
Concatenation
One of the most common operations when working with lists is concatenation. In Haskell, this is done using the ++ operator:
ghci> [1,2,3,4] ++ [9,10,11,12]
[1,2,3,4,9,10,11,12]
ghci> "hello" ++ " " ++ "world"
"hello world"
ghci> ['w','o'] ++ ['o','t']
"woot"
Note
In Haskell, strings are really just lists of characters. For example, the string "hello" is actually the same as the list ['h','e','l','l','o']. Because of this, we can use list functions on strings, which is really handy.
Be careful when repeatedly using the ++ operator on long strings. When you put together two lists, Haskell has to walk through the entire first list (the one on the left side of ++). That’s not a problem when dealing with smaller lists, but appending something to the end of a list with fifty million entries is going to take a while.
However, adding something to the beginning of a list is a nearly instantaneous operation. We do this with the : operator (also called the cons operator):
ghci> 'A':" SMALL CAT"
"A SMALL CAT"
ghci> 5:[1,2,3,4,5]
[5,1,2,3,4,5]
Notice how in the first example, : takes a character and a list of characters (a string) as its arguments. Similarly, in the second example, : takes a number and a list of numbers. The first argument to the : operator always needs to be a single item of the same type as the values in the list it’s being added to.
The ++ operator, on the other hand, always takes two lists as arguments. Even if you’re only adding a single element to the end of a list with ++, you still have to surround that item with square brackets, so Haskell will treat it like a list:
ghci> [1,2,3,4] ++ [5]
[1,2,3,4,5]
Writing [1,2,3,4] ++ 5 is wrong, because both parameters to ++ should be lists, and 5 isn’t a list; it’s a number.
Interestingly, in Haskell, [1,2,3] is just syntactic sugar for 1:2:3:[]. [] is an empty list. If we prepend 3 to that, it becomes [3]. Then if we prepend 2 to that, it becomes [2,3], and so on.
Note
[], [[]] and [[],[],[]] are all different things. The first is an empty list, the second is a list that contains one empty list, and the third is a list that contains three empty lists.
Accessing List Elements
If you want to get an element of a list by index, use the !! operator. As with most programming languages, the indices start at 0:
ghci> "Steve Buscemi" !! 6
'B'
ghci> [9.4,33.2,96.2,11.2,23.25] !! 1
33.2
However, if you try (say) to get the sixth element from a list that only has four elements, you’ll get an error, so be careful!
Lists Inside Lists
Lists can contain lists as elements, and lists can contain lists that contain lists, and so on. . . .
ghci> let b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b ++ [[1,1,1,1]]
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3],[1,1,1,1]]
ghci> [6,6,6]:b
[[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b !! 2
[1,2,2,3,4]
Lists within a list can be of different lengths, but they can’t be of different types. Just like you can’t have a list that has some characters and some numbers as elements, you also can’t have a list that contains some lists of characters and some lists of numbers.
Comparing Lists
Lists can be compared if the items they contain can be compared. When using <, <=, >= and > to compare two lists, they are compared in lexicographical order. This means that first the two list heads are compared, and if they’re equal, the second elements are compared. If the second elements are also equal, the third elements are compared, and so on, until differing elements are found. The order of the two lists is determined by the order of the first pair of differing elements.
For example, when we evaluate [3,4,2] < [3,4,3],