| Lists
Basic List Operations
These basic operations
- Create
- Prepend
- Iterate through
- Look up
- Sub-chunks
Are fairly intuitive, I think. You can figure them out by studying
this one example:
| file: printl.hs |
| 1 | -- create a list |
| 2 | a = [1,2,3,4] |
| 3 | |
| 4 | -- prepend an element to a list |
| 5 | b = 0 : a |
| 6 | |
| 7 | -- iterate through a list and print |
| 8 | foo [] = putStr "" |
| 9 | foo a = |
| 10 | do |
| 11 | putStrLn(show(head a)) |
| 12 | foo(tail a) |
| 13 | |
| 14 | main = |
| 15 | do |
| 16 | putStrLn(show(b)) |
| 17 | foo b |
| 18 | -- look up element 3 of the list |
| 19 | putStrLn("b!!3="++show(b!!3)) |
| 20 | putStrLn("b!!0 to b!!3="++show(take 4 b)) |
| 21 | putStrLn("tail b="++show(tail b)) |
> ghc --make printl.hs; ./printl
[1 of 1] Compiling Main ( printl.hs, printl.o ) Linking printl ... [0,1,2,3,4] 0 1 2 3 4 b!!3=3 b!!0 to b!!3=[0,1,2,3] tail b=[1,2,3,4]
|
Sequences
Haskell has a convenient shorthand for making sequential lists of
integers:
| file: seq.hs |
| 1 | main = putStrLn(show([3..9])) |
> ghc --make seq.hs; ./seq
[1 of 1] Compiling Main ( seq.hs, seq.o ) Linking seq ... [3,4,5,6,7,8,9]
|
The construct [3..9] means make a list of integers beginning with 3
and ending with 9, inclusive.
List Comprehensions
Haskell has a simple notation for generating a list from a function
or functions:
| file: comp.hs |
| 1 | main = putStrLn(show([ n*n | n <- [0..10]])) |
> ghc --make comp.hs; ./comp
[1 of 1] Compiling Main ( comp.hs, comp.o ) Linking comp ... [0,1,4,9,16,25,36,49,64,81,100]
|
This describes a list that is constructed from a sequential list that
goes from one to 10.
This is another way to write a "loop" in Haskell.
You can also put a conditional to exclude certain values. In this
example, we exclude n == 5.
| file: comp2.hs |
| 1 | main = putStrLn(show([ n*n | n <- [0..10], n /= 5])) |
> ghc --make comp2.hs; ./comp2
[1 of 1] Compiling Main ( comp2.hs, comp2.o ) Linking comp2 ... [0,1,4,9,16,36,49,64,81,100]
|
Note that /= means "not equals."
Infinite Lists
Because Haskell evaluates expressions lazily, it is possible to
define an infinite list and lookup it's elements. Haskell is smart
enough to only compute as much of the list as you actually use.
| file: infl.hs |
| 1 | infl1 = 0 : 1 : [ 1+n | n <- tail infl1 ] |
| 2 | infl2 = 0 : 1 : 2 : [ 1+n | n <- tail infl2 ] |
| 3 | |
| 4 | main = |
| 5 | do |
| 6 | putStrLn(show(take 10 infl1)) |
| 7 | putStrLn(show(take 10 infl2)) |
> ghc --make infl.hs; ./infl
[1 of 1] Compiling Main ( infl.hs, infl.o ) Linking infl ... [0,1,2,3,4,5,6,7,8,9] [0,1,2,2,3,3,4,4,5,5]
|
The way Haskell seems to process this is to build the list up in
steps. For infl2, we begin with the list [0,1,2]. It takes the
tail, [1,2], and feeds that into the list comprehension generating
the new elements [2,3], making the list [0,1,2,2,3]. Next it processes
the new pieces of the array using the list comprehension generating
[3,4], and making the complete list [0,1,2,2,3,3,4].
Here we use an infinite array to store all the Fibonnaci numbers.
This is more efficient than our recursive function definition earlier.
| file: fiba.hs |
| 1 | fib = 1 : 1 : [ fib!!(n-1)+fib!!(n-2) | n <- [2..]] |
| 2 | |
| 3 | main = putStrLn(show(take 10 fib)) |
> ghc --make fiba.hs; ./fiba
[1 of 1] Compiling Main ( fiba.hs, fiba.o ) Linking fiba ... [1,1,2,3,5,8,13,21,34,55]
|
Note the use of [2..] to create a list of integers from 2 to infinity.
| |