-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChapter14_2.hs
More file actions
341 lines (225 loc) · 7.63 KB
/
Copy pathChapter14_2.hs
File metadata and controls
341 lines (225 loc) · 7.63 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
339
--------------------------------------------------------------------
-- 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.