-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSet6.hs
267 lines (226 loc) · 8.21 KB
/
Set6.hs
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
-- Exercise set 6: defining classes and instances
module Set6 where
import Mooc.Todo
import Data.Char (toLower)
------------------------------------------------------------------------------
-- Ex 1: define an Eq instance for the type Country below. You'll need
-- to use pattern matching.
data Country = Finland | Switzerland | Norway
deriving Show
instance Eq Country where
Finland == Finland = True
Switzerland == Switzerland = True
Norway == Norway = True
_ == _ = False
------------------------------------------------------------------------------
-- Ex 2: implement an Ord instance for Country so that
-- Finland <= Norway <= Switzerland
--
-- Remember minimal complete definitions!
instance Ord Country where
Finland <= Norway = True
Norway <= Switzerland = True
Finland <= Switzerland = True
a <= b = a == b
------------------------------------------------------------------------------
-- Ex 3: Implement an Eq instance for the type Name which contains a String.
-- The Eq instance should ignore capitalization.
--
-- Hint: use the function Data.Char.toLower that has been imported for you.
--
-- Examples:
-- Name "Pekka" == Name "pekka" ==> True
-- Name "Pekka!" == Name "pekka" ==> False
data Name = Name String
deriving Show
instance Eq Name where
Name a == Name b = map toLower a == map toLower b
------------------------------------------------------------------------------
-- Ex 4: here is a list type parameterized over the type it contains.
-- Implement an instance "Eq (List a)" that compares the lists element
-- by element.
--
-- Note how the instance needs an Eq a constraint. What happens if you
-- remove it?
data List a = Empty | LNode a (List a)
deriving Show
instance Eq a => Eq (List a) where
Empty == Empty = True
LNode a l1 == LNode b l2 = a == b && l1 == l2
_ == _ = False
------------------------------------------------------------------------------
-- Ex 5: below you'll find two datatypes, Egg and Milk. Implement a
-- type class Price, containing a function price. The price function
-- should return the price of an item.
--
-- The prices should be as follows:
-- * chicken eggs cost 20
-- * chocolate eggs cost 30
-- * milk costs 15 per liter
--
-- Example:
-- price ChickenEgg ==> 20
data Egg = ChickenEgg | ChocolateEgg
deriving Show
data Milk = Milk Int -- amount in litres
deriving Show
class Price a where
price :: a -> Int
instance Price Egg where
price ChickenEgg = 20
price ChocolateEgg = 30
instance Price Milk where
price (Milk n) = 15 * n
------------------------------------------------------------------------------
-- Ex 6: define the necessary instance hierarchy in order to be able
-- to compute these:
--
-- price (Just ChickenEgg) ==> 20
-- price [Milk 1, Milk 2] ==> 45
-- price [Just ChocolateEgg, Nothing, Just ChickenEgg] ==> 50
-- price [Nothing, Nothing, Just (Milk 1), Just (Milk 2)] ==> 45
instance Price a => Price (Maybe a) where
price Nothing = 0
price (Just a) = price a
instance Price a => Price [a] where
price = sum . map price
------------------------------------------------------------------------------
-- Ex 7: below you'll find the datatype Number, which is either an
-- Integer, or a special value Infinite.
--
-- Implement an Ord instance so that finite Numbers compare normally,
-- and Infinite is greater than any other value.
data Number = Finite Integer | Infinite
deriving (Show,Eq)
instance Ord Number where
Finite x <= Finite y = x <= y
_ <= Infinite = True
_ <= _ = False
------------------------------------------------------------------------------
-- Ex 8: rational numbers have a numerator and a denominator that are
-- integers, usually separated by a horizontal bar or a slash:
--
-- numerator
-- ------------- == numerator / denominator
-- denominator
--
-- You may remember from school that two rationals a/b and c/d are
-- equal when a*d == b*c. Implement the Eq instance for rationals
-- using this definition.
--
-- You may assume in all exercises that the denominator is always
-- positive and nonzero.
--
-- Examples:
-- RationalNumber 4 5 == RationalNumber 4 5 ==> True
-- RationalNumber 12 15 == RationalNumber 4 5 ==> True
-- RationalNumber 13 15 == RationalNumber 4 5 ==> False
data RationalNumber = RationalNumber Integer Integer
deriving Show
instance Eq RationalNumber where
RationalNumber a b == RationalNumber c d = a * d == b * c
------------------------------------------------------------------------------
-- Ex 9: implement the function simplify, which simplifies a rational
-- number by removing common factors of the numerator and denominator.
-- In other words,
--
-- ca a
-- ---- ==> ---
-- cb b
--
-- As a concrete example,
--
-- 12 3 * 4 4
-- ---- == ------- ==> ---.
-- 15 3 * 5 5
--
-- Hint: Remember the function gcd?
simplify :: RationalNumber -> RationalNumber
simplify (RationalNumber a b) = RationalNumber (a `div` d) (b `div` d) where d = gcd a b
------------------------------------------------------------------------------
-- Ex 10: implement the typeclass Num for RationalNumber. The results
-- of addition and multiplication must be simplified.
--
-- Reminders:
-- * negate x is 0-x
-- * abs is absolute value
-- * signum is -1, +1 or 0 depending on the sign of the input
--
-- Examples:
-- RationalNumber 1 3 + RationalNumber 1 6 ==> RationalNumber 1 2
-- RationalNumber 1 3 * RationalNumber 3 1 ==> RationalNumber 1 1
-- negate (RationalNumber 2 3) ==> RationalNumber (-2) 3
-- fromInteger 17 :: RationalNumber ==> RationalNumber 17 1
-- abs (RationalNumber (-3) 2) ==> RationalNumber 3 2
-- signum (RationalNumber (-3) 2) ==> RationalNumber (-1) 1
-- signum (RationalNumber 0 2) ==> RationalNumber 0 1
instance Num RationalNumber where
RationalNumber a b + RationalNumber c d = simplify $ RationalNumber (a * d + b * c) (b * d)
RationalNumber a b * RationalNumber c d = simplify $ RationalNumber (a * c) (b * d)
abs (RationalNumber a b) = RationalNumber (abs a) (abs b)
negate (RationalNumber a b) = RationalNumber (-a) b
signum (RationalNumber a b) = RationalNumber (signum a) 1
fromInteger a = RationalNumber a 1
------------------------------------------------------------------------------
-- Ex 11: a class for adding things. Define a class Addable with a
-- constant `zero` and a function `add`. Define instances of Addable
-- for Integers and lists. Numbers are added with the usual addition,
-- while lists are added by catenating them. Pick a value for `zero`
-- such that: `add zero x == x`
--
-- Examples:
-- add 1 2 ==> 3
-- add 1 zero ==> 1
-- add [1,2] [3,4] ==> [1,2,3,4]
-- add zero [True,False] ==> [True,False]
class Addable a where
zero :: a
add :: a -> a -> a
instance Addable Integer where
zero = 0
add = (+)
instance Addable [a] where
zero = []
add = (++)
------------------------------------------------------------------------------
-- Ex 12: cycling. Implement a type class Cycle that contains a
-- function `step` that cycles through the values of the type.
-- Implement instances for Color and Suit that work like this:
--
-- step Red ==> Green
-- step Green ==> Blue
-- step Blue ==> Red
--
-- The suit instance should cycle suits in the order Club, Spade,
-- Diamond, Heart, Club.
--
-- Also add a function `stepMany` to the class and give it a default
-- implementation using `step`. The function `stepMany` should take
-- multiple (determined by an Int argument) steps like this:
--
-- stepMany 2 Club ==> Diamond
-- stepMany 3 Diamond ==> Spade
--
-- The tests will test the Cycle class and your default implementation
-- of stepMany by adding an instance like this:
--
-- instance Cycle Int where
-- step = succ
data Color = Red | Green | Blue
deriving (Show, Eq)
data Suit = Club | Spade | Diamond | Heart
deriving (Show, Eq)
class Cycle a where
step :: a -> a
stepMany :: Int -> a -> a
stepMany 0 a = a
stepMany n a = stepMany (n - 1) (step a)
instance Cycle Color where
step Red = Green
step Green = Blue
step Blue = Red
instance Cycle Suit where
step Club = Spade
step Spade = Diamond
step Diamond = Heart
step Heart = Club