1
1
{-# LANGUAGE NoImplicitPrelude #-}
2
2
module ITMOPrelude.List where
3
3
4
- import Prelude (Show ,Read ,error )
4
+ import Prelude (Show ,Read ,error , show )
5
+ import qualified Prelude as P ((++) )
5
6
import ITMOPrelude.Primitive
6
7
7
8
---------------------------------------------
@@ -13,98 +14,151 @@ import ITMOPrelude.Primitive
13
14
---------------------------------------------
14
15
-- Определение
15
16
16
- data List a = Nil | Cons a (List a ) deriving (Show ,Read )
17
+ data List a = Nil | Cons a (List a ) deriving (Read )
18
+
19
+ instance Show a => Show (List a ) where
20
+ show lst@ (Cons x xs) = (P. ++) " [" (showList lst)
21
+ show Nil = " []"
22
+
23
+ showList (Cons x Nil ) = (P. ++) (show x) " ]"
24
+ showList (Cons x xs) = (P. ++) (show x) ((P. ++) " , " (showList xs))
17
25
18
26
---------------------------------------------
19
27
-- Операции
20
28
21
29
-- Длина списка
22
30
length :: List a -> Nat
23
- length = undefined
31
+ length xs = foldr plusOne Zero xs
32
+ where plusOne elem n = Succ n
24
33
25
34
-- Склеить два списка за O(length a)
26
35
(++) :: List a -> List a -> List a
27
- a ++ b = undefined
36
+ Nil ++ b = b
37
+ (Cons x xs) ++ b = Cons x (xs ++ b)
28
38
29
39
-- Список без первого элемента
30
40
tail :: List a -> List a
31
- tail = undefined
41
+ tail Nil = error " List.tail: empty list"
42
+ tail (Cons x xs) = xs
32
43
33
44
-- Список без последнего элемента
34
45
init :: List a -> List a
35
- init = undefined
46
+ init Nil = error " List.init: empty list"
47
+ init (Cons x Nil ) = Nil
48
+ init (x `Cons ` xs) = x `Cons ` (init xs)
36
49
37
50
-- Первый элемент
38
51
head :: List a -> a
39
- head = undefined
52
+ head Nil = error " List.head: empty list"
53
+ head (Cons x xs) = x
40
54
41
55
-- Последний элемент
42
56
last :: List a -> a
43
- last = undefined
57
+ last Nil = error " List.last: empty list"
58
+ last (Cons x Nil ) = x
59
+ last (Cons x xs) = last xs
44
60
45
61
-- n первых элементов списка
46
62
take :: Nat -> List a -> List a
47
- take = undefined
63
+ take Zero xs = Nil
64
+ take (Succ _) Nil = Nil
65
+ take (Succ n) (Cons x xs) = Cons x $ take n xs
48
66
49
67
-- Список без n первых элементов
50
68
drop :: Nat -> List a -> List a
51
- drop = undefined
69
+ drop Zero xs = xs
70
+ drop (Succ _) Nil = Nil
71
+ drop (Succ n) (Cons x xs) = drop n xs
52
72
53
73
-- Оставить в списке только элементы удовлетворяющие p
54
74
filter :: (a -> Bool ) -> List a -> List a
55
- filter p = undefined
75
+ filter p Nil = Nil
76
+ filter p (Cons x xs) = if' (p x) (Cons x $ filter p xs) (filter p xs)
56
77
57
78
-- Обобщённая версия. Вместо "выбросить/оставить" p
58
79
-- говорит "выбросить/оставить b".
59
80
gfilter :: (a -> Maybe b ) -> List a -> List b
60
- gfilter p = undefined
81
+ gfilter f Nil = Nil
82
+ gfilter f (Cons x xs) = case f x of
83
+ Just y -> Cons y (gfilter f xs)
84
+ Nothing -> gfilter f xs
61
85
62
86
-- Копировать из списка в результат до первого нарушения предиката
63
87
-- takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]
64
88
takeWhile :: (a -> Bool ) -> List a -> List a
65
- takeWhile = undefined
89
+ takeWhile p Nil = Nil
90
+ takeWhile p (Cons x xs) = if' (p x) (Cons x $ takeWhile p xs) Nil
66
91
67
92
-- Не копировать из списка в результат до первого нарушения предиката,
68
93
-- после чего скопировать все элементы, включая первый нарушивший
69
94
-- dropWhile (< 3) [1,2,3,4,1,2,3,4] == [3,4,1,2,3,4]
70
95
dropWhile :: (a -> Bool ) -> List a -> List a
71
- dropWhile = undefined
96
+ dropWhile p Nil = Nil
97
+ dropWhile p lst@ (Cons x xs) = if' (p x) (dropWhile p xs) lst
72
98
73
99
-- Разбить список в пару (найбольший префикс удовлетворяющий p, всё остальное)
74
100
span :: (a -> Bool ) -> List a -> Pair (List a ) (List a )
75
- span p = undefined
101
+ span p Nil = Pair Nil Nil
102
+ span p lst@ (Cons x xs) = if' (p x)
103
+ (let (Pair ts ds) = span p xs
104
+ in Pair (Cons x ts) ds)
105
+ (Pair Nil lst)
76
106
77
- -- Разбить список по предикату на (takeWhile p xs, dropWhile p xs),
107
+ -- Разбить список по предикату на (takeWhile (not . p) xs, dropWhile (not . p) xs),
78
108
-- но эффективнее
79
109
break :: (a -> Bool ) -> List a -> Pair (List a ) (List a )
80
- break = undefined
110
+ break p = span ( not . p)
81
111
82
112
-- n-ый элемент списка (считая с нуля)
83
113
(!!) :: List a -> Nat -> a
84
114
Nil !! n = error " !!: empty list"
85
- l !! n = undefined
115
+ (Cons x xs) !! Zero = x
116
+ (Cons x xs) !! (Succ n) = xs !! n
86
117
87
118
-- Список задом на перёд
88
119
reverse :: List a -> List a
89
- reverse = undefined
120
+ reverse = helper Nil
121
+ where helper acc (Cons x xs) = helper (Cons x acc) xs
122
+ helper acc Nil = acc
123
+
124
+
90
125
91
126
-- (*) Все подсписки данного списка
92
127
subsequences :: List a -> List (List a )
93
128
subsequences Nil = Cons Nil Nil
94
- subsequences (Cons x xs) = undefined
129
+ subsequences (Cons x xs) = childsubseq ++ (mapcons x (startswith xs))
130
+ where childsubseq = subsequences xs
131
+ mapcons x = map (Cons x)
132
+ startswith Nil = Cons Nil Nil
133
+ startswith (Cons x xs) = Cons Nil (mapcons x (startswith xs))
95
134
96
135
-- (*) Все перестановки элементов данного списка
97
136
permutations :: List a -> List (List a )
98
- permutations = undefined
137
+ permutations Nil = Cons Nil Nil
138
+ permutations (Cons x xs) = flatmap (insert x) $ permutations xs
139
+ where insert x xs = insert' (length xs)
140
+ where insert' Zero = Cons (Cons x xs) Nil
141
+ insert' n@ (Succ nd) = ((take n xs) ++ (Cons x Nil ) ++ (drop n xs)) `Cons ` (insert' nd)
142
+
99
143
100
144
-- (*) Если можете. Все перестановки элементов данного списка
101
145
-- другим способом
102
146
permutations' :: List a -> List (List a )
103
- permutations' = undefined
147
+ permutations' Nil = Cons Nil Nil
148
+ permutations' xs = concatMap helper (range (length xs))
149
+ where helper n = map (Cons $ xs !! n) (permutations' (dropn n xs))
150
+ range n = range' n Nil
151
+ where range' Zero acc = acc
152
+ range' (Succ n) acc = range' n (n `Cons ` acc)
153
+ dropn _ Nil = Nil
154
+ dropn Zero (Cons x xs) = xs
155
+ dropn (Succ n) (Cons x xs) = Cons x $ dropn n xs
156
+
157
+ flatmap p xs = foldr (++) Nil (map p xs)
104
158
105
159
-- Повторяет элемент бесконечное число раз
106
160
repeat :: a -> List a
107
- repeat = undefined
161
+ repeat x = Cons x $ repeat x
108
162
109
163
-- Левая свёртка
110
164
-- порождает такое дерево вычислений:
@@ -118,12 +172,14 @@ repeat = undefined
118
172
-- / \
119
173
-- z l!!0
120
174
foldl :: (a -> b -> a ) -> a -> List b -> a
121
- foldl f z l = undefined
175
+ foldl f z (Cons x xs) = foldl f (f z x) xs
176
+ foldl f z Nil = z
122
177
123
178
-- Тот же foldl, но в списке оказываются все промежуточные результаты
124
179
-- last (scanl f z xs) == foldl f z xs
125
180
scanl :: (a -> b -> a ) -> a -> List b -> List a
126
- scanl = undefined
181
+ scanl f z (Cons x xs) = (f z x) `Cons ` (scanl f (f z x) xs)
182
+ scanl f z Nil = (Cons z Nil )
127
183
128
184
-- Правая свёртка
129
185
-- порождает такое дерево вычислений:
@@ -138,32 +194,39 @@ scanl = undefined
138
194
-- z
139
195
--
140
196
foldr :: (a -> b -> b ) -> b -> List a -> b
141
- foldr f z l = undefined
197
+ foldr f z (Cons x xs) = f x $ foldr f z xs
198
+ foldr f z Nil = z
142
199
143
200
-- Аналогично
144
201
-- head (scanr f z xs) == foldr f z xs.
145
- scanr :: (a -> b -> b ) -> b -> [a ] -> [b ]
146
- scanr = undefined
202
+ scanr :: (a -> b -> b ) -> b -> List a -> List b
203
+ scanr f z Nil = Cons z Nil
204
+ scanr f z (Cons x xs) = (f x $ head helper) `Cons ` helper
205
+ where helper = scanr f z xs
147
206
148
207
-- Должно завершаться за конечное время
149
208
finiteTimeTest = take (Succ $ Succ $ Succ $ Succ Zero ) $ foldr (Cons ) Nil $ repeat Zero
150
209
151
210
-- Применяет f к каждому элементу списка
152
211
map :: (a -> b ) -> List a -> List b
153
- map f l = undefined
212
+ map f = foldr helper Nil
213
+ where helper a xs = (f a) `Cons ` xs
154
214
155
215
-- Склеивает список списков в список
156
216
concat :: List (List a ) -> List a
157
- concat = undefined
217
+ concat = foldr (++) Nil
158
218
159
219
-- Эквивалент (concat . map), но эффективнее
160
220
concatMap :: (a -> List b ) -> List a -> List b
161
- concatMap = undefined
221
+ concatMap f (Cons x xs) = (f x) ++ (concatMap f xs)
222
+ concatMap f Nil = Nil
162
223
163
224
-- Сплющить два списка в список пар длинны min (length a, length b)
164
225
zip :: List a -> List b -> List (Pair a b )
165
- zip a b = undefined
226
+ zip = zipWith Pair
166
227
167
228
-- Аналогично, но плющить при помощи функции, а не конструктором Pair
168
229
zipWith :: (a -> b -> c ) -> List a -> List b -> List c
169
- zipWith = undefined
230
+ zipWith f (Cons x xs) (Cons y ys) = (f x y) `Cons ` (zipWith f xs ys)
231
+ zipWith f Nil ys = Nil
232
+ zipWith f xs Nil = Nil
0 commit comments