-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChapter14_2.lhs
More file actions
340 lines (218 loc) · 7.51 KB
/
Copy pathChapter14_2.lhs
File metadata and controls
340 lines (218 loc) · 7.51 KB
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
Haskell: The Craft of Functional Programming
Simon Thompson
(c) Addison-Wesley, 1999.
Chapter 14, part 2
> module Chapter14_2 where
> import Prelude hiding (Either(..),either,Maybe(..),maybe)
> import Chapter14_1 hiding (Name,Shape(..))
Algebraic types, part 2
^^^^^^^^^^^^^^^^^^^^^^^
Polymorphic algebraic types
^^^^^^^^^^^^^^^^^^^^^^^^^^^
A type of pairs of elements, taken from the same type.
> data Pairs a = Pr a a
and example elements of the type are
> pair1 = Pr 2 3 :: Pairs Int
> pair2 = Pr [] [3] :: Pairs [Int]
> pair3 = Pr [] [] :: Pairs [a]
Are the two halves equal?
> equalPair :: Eq a => Pairs a -> Bool
> equalPair (Pr x y) = (x==y)
Lists
^^^^^
Defining lists from scratch (which loses some of the special syntax for
lists).
> data List a = NilList | Cons a (List a)
> deriving (Eq,Ord,Show,Read)
Binary trees
^^^^^^^^^^^^
Binary trees carrying elements of an arbitrary type.
> data Tree a = Nil | Node a (Tree a) (Tree a)
> deriving (Eq,Ord,Show,Read)
The depth of a binary tree.
> depthT :: Tree a -> Int
> depthT Nil = 0
> depthT (Node n t1 t2) = 1 + max (depthT t1) (depthT t2)
Turning a tree into a list.
> collapse :: Tree a -> [a]
> collapse Nil = []
> collapse (Node x t1 t2)
> = collapse t1 ++ [x] ++ collapse t2
For example,
> collapseEG
> = collapse (Node 12
> (Node 34 Nil Nil)
> (Node 3 (Node 17 Nil Nil) Nil))
Mapping a function over all elements in a tree, preserving the
structure.
> mapTree :: (a -> b) -> Tree a -> Tree b
> mapTree f Nil = Nil
> mapTree f (Node x t1 t2)
> = Node (f x) (mapTree f t1) (mapTree f t2)
The union type, Either
^^^^^^^^^^^^^^^^^^^^^^
A union type -- defined in the Prelude.lhs.
> data Either a b = Left a | Right b
> deriving (Eq,Ord,Read,Show)
Examples
> eitherEG1 = Left "Duke of Prunes" :: Either String Int
> eitherEG2 = Right 33312 :: Either String Int
In the left or the right?
> isLeft :: Either a b -> Bool
> isLeft (Left _) = True
> isLeft (Right _) = False
To define a function from Either a b to c we have to deal with two cases,
> either :: (a -> c) -> (b -> c) -> Either a b -> c
> either f g (Left x) = f x
> either f g (Right y) = g y
If we have a function f::a -> cand we wish to apply it to an element
of Either a b, there is a problem: what do we do if the element is
in the right-hand side of the Either type? A simple answer is to raise an error
> applyLeft :: (a -> c) -> Either a b -> c
> applyLeft f (Left x) = f x
> applyLeft f (Right _) = error "applyLeft applied to Right"
Arbitrarily branching trees
> data GTree a = Leaf a | Gnode [GTree a]
Case study: Program Errors
^^^^^^^^^^^^^^^^^^^^^^^^^^
This section explores various ways of handling errors raised in program
execution.
\subsection*{Dummy Values}
\index{dummy values at errors}
The tail function re-defined to give an empty list when applied to the empty list.
> tl :: [a] -> [a]
> tl (_:xs) = xs
> tl [] = []
Zero returned when division by zero,
> divide :: Int -> Int -> Int
> divide n m
> | (m /= 0) = n `div` m
> | otherwise = 0
Head redefined to give a dummy value on the empty list; the value has
to be a parameter.
> hd :: a -> [a] -> a
> hd y (x:_) = x
> hd y [] = y
Error types
^^^^^^^^^^^
The Maybe type, as defined in the Prelude.lhs,
> data Maybe a = Nothing | Just a
> deriving (Eq,Ord,Read,Show)
An error-raising division function
> errDiv :: Int -> Int -> Maybe Int
> errDiv n m
> | (m /= 0) = Just (n `div` m)
> | otherwise = Nothing
The function mapMaybe transmits an error value though the application of
the function g.
> mapMaybe :: (a -> b) -> Maybe a -> Maybe b
> mapMaybe g Nothing = Nothing
> mapMaybe g (Just x) = Just (g x)
In trapping an error, we aim to return a result of type b, from an
input of type Maybe a; there are two cases to deal with:
normal result (Just); error (Nothing).
> maybe :: b -> (a -> b) -> Maybe a -> b
> maybe n f Nothing = n
> maybe n f (Just x) = f x
Examples
> handle1, handle2 :: Int
> handle1 = maybe 56 (1+) (mapMaybe (*3) (errDiv 9 0))
> handle2 = maybe 56 (1+) (mapMaybe (*3) (errDiv 9 1))
Generalising the Maybe type to include an error message in the `Nothing'
part.
> data Err a = OK a | Error String
Design with Algebraic Data Types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Case study: edit distance
^^^^^^^^^^^^^^^^^^^^^^^^^
A type to represent the different sorts of Edit operations.
> data Edit = Change Char |
> Copy |
> Delete |
> Insert Char |
> Kill
> deriving (Eq,Show)
Transforming one string into another, optimally,
> transform :: String -> String -> [Edit]
> transform [] [] = []
> transform xs [] = [Kill]
> transform [] ys = map Insert ys
> transform (x:xs) (y:ys)
> | x==y = Copy : transform xs ys
> | otherwise = best [ Delete : transform xs (y:ys) ,
> Insert y : transform (x:xs) ys ,
> Change y : transform xs ys ]
How do we choose the best sequence? We choose the one with the lowest
cost.
> best :: [[Edit]] -> [Edit]
> best [x] = x
> best (x:xs)
> | cost x <= cost b = x
> | otherwise = b
> where
> b = best xs
The cost is given by charging one for every operation except copy,
which is equivalent to `leave unchanged'.
> cost :: [Edit] -> Int
> cost = length . filter (/=Copy)
Simulation
^^^^^^^^^^
NOTE: details of the Simulation case study are collected separately.
Algebraic types and type classes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Movable objects
^^^^^^^^^^^^^^^
> data Vector = Vec Float Float
> class Movable a where
> move :: Vector -> a -> a
> reflectX :: a -> a
> reflectY :: a -> a
> rotate180 :: a -> a
> rotate180 = reflectX . reflectY
> data Point = Point Float Float
> deriving Show
> instance Movable Point where
> move (Vec v1 v2) (Point c1 c2) = Point (c1+v1) (c2+v2)
> reflectX (Point c1 c2) = Point c1 (-c2)
> reflectY (Point c1 c2) = Point (-c1) c2
> rotate180 (Point c1 c2) = Point (-c1) (-c2)
> data Figure = Line Point Point |
> Circle Point Float
> deriving Show
> instance Movable Figure where
> move v (Line p1 p2) = Line (move v p1) (move v p2)
> move v (Circle p r) = Circle (move v p) r
> reflectX (Line p1 p2) = Line (reflectX p1) (reflectX p2)
> reflectX (Circle p r) = Circle (reflectX p) r
> reflectY (Line p1 p2) = Line (reflectY p1) (reflectY p2)
> reflectY (Circle p r) = Circle (reflectY p) r
> instance Movable a => Movable [a] where
> move v = map (move v)
> reflectX = map reflectX
> reflectY = map reflectY
Named objects
^^^^^^^^^^^^^
Named objects:
> class Named a where
> lookName :: a -> String
> giveName :: String -> a -> a
A named type ...
> data Name a = Pair a String
... as witnessed by the instance declaration.
> instance Named (Name a) where
> lookName (Pair obj nm) = nm
> giveName nm (Pair obj _) = (Pair obj nm)
Putting together classes
^^^^^^^^^^^^^^^^^^^^^^^^
See the text for details of what is going on here.
> mapName :: (a -> b) -> Name a -> Name b
> mapName f (Pair obj nm) = Pair (f obj) nm
> instance Movable a => Movable (Name a) where
> move v = mapName (move v)
> reflectX = mapName reflectX
> reflectY = mapName reflectY
> class (Movable b, Named b) => NamedMovable b
> instance Movable a => NamedMovable (Name a)
Reasoning about algebraic types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The functions discussed here are all defined elsewhere.