File: part25.lhs

package info (click to toggle)
haskell98-tutorial 200006-2-3
  • links: PTS
  • area: main
  • in suites: bullseye
  • size: 972 kB
  • sloc: haskell: 2,125; makefile: 68; sh: 9
file content (209 lines) | stat: -rw-r--r-- 6,844 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
Gentle Introduction to Haskell 98, Online Supplement 
Part 25
Covers Sections 13, 13.1, 13.2, 13.3, 13.4, 13.5

> module Part25() where

> import Array

Section: 13  Arrays
Section: 13.1  Index Types

Arrays are built on the class Ix.  Here are some quick examples of Ix:

> e1 :: [Int]
> e1 = range (0,4)
> e2 :: Int
> e2 = index (0,4) 2
> low,high :: (Int,Int)
> low = (1,1)
> high = (3,4)
> e3 = range (low,high)
> e4 = index (low,high) (3,2)
> e5 = inRange (low,high) (4,3)

Section: 13.2  Array Creation

> squares :: Array Int Int
> squares = array (1,100) [(i,i*i) | i <- [1..100]]

We can also parameterize this a little:

> squares' :: Int -> Array Int Int
> squares' n = array (1,n) [(i,i*i) | i <- [1..n]]

> e6 :: Int
> e6 = squares!6
> e7 :: (Int,Int)
> e7 = bounds squares
> e8 :: Array Int Int
> e8 = squares' 10

Here is a function which corresponds to `take' for lists.  It takes
an arbitrary slice out of an array.

> atake :: (Ix a) => Array a b -> (a,a) -> Array a b
> atake a (l,u) | inRange (bounds a) l && inRange (bounds a) u =
>                    array (l,u) [(i,a!i) | i <- range (l,u)]
>               | otherwise = error "Subarray out of range"

> e9 = atake squares (4,8)

> mkArray :: Ix a => (a -> b) -> (a,a) -> Array a b
> mkArray f bnds = array bnds [(i,f i) | i <- range bnds]

> e10 :: Array Int Int
> e10 = mkArray (\i -> i*i) (1,10)

> fibs :: Int -> Array Int Int
> fibs n = a where
>             a = array (0,n) ([(0,1), (1,1)] ++
>                              [(i,a!(i-1) + a!(i-2)) | i <- [2..n]])

> e11 = atake (fibs 50) (3,10)

> wavefront :: Int -> Array (Int,Int) Int
> wavefront n = a where
>                 a = array ((1,1),(n,n))
>                      ([((1,j),1) | j <- [1..n]] ++
>                       [((i,1),1) | i <- [2..n]] ++
>                       [((i,j),a!(i,j-1) + a!(i-1,j-1) + a!(i-1,j))
>                                   | i <- [2..n], j <- [2..n]])

> wave = wavefront 20
> e12 = atake wave ((1,1),(3,3))
> e13 = atake wave ((3,3),(5,5))

Here are some errors in array operations:

> e14 :: Int
> e14 = wave ! (0,0)  -- Out of bounds
> arr1 :: Array Int Int
> arr1 = array (1,10) [(1,1)] -- No value provided for 2..10
> e15,e16 :: Int
> e15 = arr1 ! 1  -- works OK
> e16 = arr1 ! 2  -- undefined by array

Section: 13.3  Accumulation

> hist :: (Ix a, Integral b) => (a,a) -> [a] -> Array a b
> hist bnds is = accumArray (+) 0 bnds [(i,1) | i <- is, inRange bnds i]

> e17 :: Array Char Int
> e17 = hist ('a','z') "This counts the frequencies of each lowercase letter"

> decades :: (RealFrac a) => a -> a -> [a] -> Array Int Int
> decades a b = hist (0,9) . map decade
>                 where
>                   decade x = floor ((x-a) * s)
>                   s = 10 / (b - a)

> test1 :: [Float]
> test1 = map sin [0..100]  -- take the sine of the 0 - 100
> e18 = decades 0 1 test1

Section: 13.4  Incremental Updates

> swapRows :: (Ix a, Ix b, Enum b) => a -> a -> Array (a,b) c -> Array (a,b) c
> swapRows i i' a = a // ([((i,j),a!(i',j)) | j <- [jLo..jHi]] ++
> 			  [((i',j),a!(i,j)) | j <- [jLo..jHi]])
>                where ((iLo,jLo),(iHi,jHi)) = bounds a

> arr2 :: Array (Int,Int) (Int,Int)
> arr2 = array ((1,1),(5,5)) [((i,j),(i,j)) | (i,j) <- range ((1,1),(5,5))]

> e19 = swapRows 2 3 arr2

Printing the arrays in more readable form makes the results easier
to view.

This is a printer for 2d arrays; width is # of columns per element 

> aprint :: (Show b) => Array (Int, Int) b -> Int -> ShowS
> aprint a width = shows (bounds a) . showChar '\n' . showRows lx ly where
>   showRows r c | r > ux = showChar '\n'
>   showRows r c | c > uy = showChar '\n' . showRows (r+1) ly
>   showRows r c = showElt (a!(r,c)) . showRows r (c+1)
>   showElt e = showString (take width (show e ++ repeat ' ')) . showChar ' '
>   ((lx,ly),(ux,uy)) = bounds a

> showArray :: (Show b) => Array (Int, Int) b -> Int -> IO ()
> showArray a w = putStrLn (aprint a w "") 

> e20 = showArray e19 6

> swapRows' :: (Ix a, Ix b, Enum b) => a -> a -> Array (a,b) c -> Array (a,b) c
> swapRows' i i' a = a // [assoc | j <- [jLo..jHi],
>                                  assoc <- [((i,j),a!(i',j)),
> 	  				     ((i',j),a!(i,j))]]
>                where ((iLo,jLo),(iHi,jHi)) = bounds a

> e21 = showArray (swapRows' 1 5 arr2) 6

Section: 13.5  An example: Matrix Multiplication

> matMult :: (Ix a, Ix b, Ix c, Num d) =>
>               Array (a,b) d -> Array (b,c) d -> Array (a,c) d
> matMult x y =
>   array resultBounds
>         [((i,j), sum [x!(i,k) * y!(k,j) | k <- range (lj,uj)])
>                   | i <- range (li,ui),
>                     j <- range (lj',uj')]
>  where
>     ((li,lj),(ui,uj)) = bounds x
>     ((li',lj'),(ui',uj')) = bounds y
>     resultBounds
>       | (lj,uj)==(li',ui')    =  ((li,lj'),(ui,uj'))
>       | otherwise             = error "matMult: incompatible bounds"

> mat1,mat2,mat3,mat4 :: Array (Int,Int) Int
> mat1 = array ((0,0),(1,1)) [((0,0),1), ((0,1),0), ((1,0),0), ((1,1),1)] 
> mat2 = array ((0,0),(1,1)) [((0,0),1), ((0,1),1), ((1,0),1), ((1,1),1)] 
> mat3 = array ((0,0),(1,1)) [((0,0),1), ((0,1),2), ((1,0),3), ((1,1),4)] 
> mat4 = array ((0,0),(1,2)) [((0,0),1), ((0,1),2), ((0,2),3), 
> 			      ((1,0),4), ((1,1),5), ((1,2),6)] 

> e22 = showArray (matMult mat1 mat2) 4
> e23 = showArray (matMult mat2 mat3) 4
> e24 = showArray (matMult mat1 mat4) 4
> e25 = showArray (matMult mat4 mat1) 4

> matMult' :: (Ix a, Ix b, Ix c, Num d) =>
>               Array (a,b) d -> Array (b,c) d -> Array (a,c) d
> matMult' x y =
>   accumArray (+) 0 ((li,lj'),(ui,uj'))
>         [((i,j), x!(i,k) * y!(k,j))
>                   | i <- range (li,ui),
>                     j <- range (lj',uj'),
>                     k <- range (lj,uj)]
>  where
>     ((li,lj),(ui,uj)) = bounds x
>     ((li',lj'),(ui',uj')) = bounds y
>     resultBounds
>        | (lj,uj)==(li',ui')    =  ((li,lj'),(ui,uj'))
>        | otherwise             = error "matMult: incompatible bounds"

> e26 = showArray (matMult mat1 mat2) 4
> e27 = showArray (matMult mat2 mat3) 4

> genMatMul :: (Ix a, Ix b, Ix c) =>
>               ([f] -> g) -> (d -> e -> f) ->
>               Array (a,b) d -> Array (b,c) e -> Array (a,c) g
> genMatMul f g x y =
>   array ((li,lj'),(ui,uj'))
>         [((i,j), f [(x!(i,k)) `g` (y!(k,j)) | k <- range (lj,uj)])
>                   | i <- range (li,ui),
>                     j <- range (lj',uj')]
>  where
>     ((li,lj),(ui,uj)) = bounds x
>     ((li',lj'),(ui',uj')) = bounds y
>     resultBounds
>          | (lj,uj)==(li',ui')    =  ((li,lj'),(ui,uj'))
>          | otherwise             = error "matMult: incompatible bounds"

> e28 = showArray (genMatMul maximum (-) mat2 mat1) 4
> e29 = showArray (genMatMul and (==) mat1 mat2) 6
> e30 = showArray (genMatMul and (==) mat1 mat1) 6

This is the end of the online supplement