Lists
Prerequisites: Values and basic types
The list is Haskell's most-used data structure. All elements of a list have the same type.
main :: IO ()
main = do
let numbers = [3, 1, 4, 1, 5] :: [Int]
names = ["Ada", "Grace", "Alan"]
print numbers
print (length numbers, head names, last names)
print (numbers ++ [9, 2])
print (0 : numbers)
print (numbers !! 2)
print (null numbers, null [])
print (reverse names)
main.hs:6:26: warning: [GHC-63394] [-Wx-partial]
In the use of `head'
(imported from Prelude, but defined in GHC.Internal.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching, 'Data.List.uncons' or 'Data.Maybe.listToMaybe' instead. Consider refactoring to use "Data.List.NonEmpty"."
|
6 | print (length numbers, head names, last names)
| ^^^^
[3,1,4,1,5]
(5,"Ada","Alan")
[3,1,4,1,5,9,2]
[0,3,1,4,1,5]
4
(False,True)
["Alan","Grace","Ada"]
++joins two lists.x : xs(cons) puts one element in front.!!gets the element at an index, counting from 0 — it's slow on long lists and crashes on a bad index, so it's rarely used.nulltests for emptiness. Prefer it tolength xs == 0, which walks the whole list.- The warning at the top comes from GHC 9.8 and later:
headcrashes on an empty list, so GHC reminds you to consider pattern matching instead. The program still runs. (lastis just as partial, but isn't flagged.)
How lists are built
A list is either empty ([]) or an element consed onto another
list. [1, 2, 3] is just nicer syntax for 1 : 2 : 3 : []:
main :: IO ()
main = do
print (1 : 2 : 3 : [])
print ([1, 2, 3] == 1 : [2, 3])
print ('H' : "askell")
[1,2,3]
True
"Haskell"
This matters because lists are singly linked: adding to the front
with : is instant, but ++ and !! have to walk the list. Build lists
by consing to the front, and reverse at the end if needed.
Strings are lists
String is just another name for [Char], so every list function works
on strings:
main :: IO ()
main = do
print (length "Haskell")
putStrLn (reverse "stressed")
print (last "Curry", "abc" ++ "def")
7
desserts
('y',"abcdef")
Lists are immutable
main :: IO ()
main = do
let original = [1, 2, 3]
extended = 0 : original
print original
print extended
[1,2,3]
[0,1,2,3]
0 : original doesn't change original. The new list shares its tail
with the old one — safe, because neither can ever be modified.
Common mistakes
- Mixing types:
[1, "two"]is a type error. Use a tuple or your own data type (Level 2) for mixed data. - Using
headorlaston a list that might be empty — use pattern matching instead (coming up soon).