Skip to content

Commit 45c45fd

Browse files
committed
lists
1 parent bc99917 commit 45c45fd

File tree

2 files changed

+100
-34
lines changed

2 files changed

+100
-34
lines changed

ITMOPrelude/List.hs

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{-# LANGUAGE NoImplicitPrelude #-}
22
module ITMOPrelude.List where
33

4-
import Prelude (Show,Read,error)
4+
import Prelude (Show,Read,error, show)
5+
import qualified Prelude as P ((++))
56
import ITMOPrelude.Primitive
67

78
---------------------------------------------
@@ -13,98 +14,151 @@ import ITMOPrelude.Primitive
1314
---------------------------------------------
1415
-- Определение
1516

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))
1725

1826
---------------------------------------------
1927
-- Операции
2028

2129
-- Длина списка
2230
length :: List a -> Nat
23-
length = undefined
31+
length xs = foldr plusOne Zero xs
32+
where plusOne elem n = Succ n
2433

2534
-- Склеить два списка за O(length a)
2635
(++) :: List a -> List a -> List a
27-
a ++ b = undefined
36+
Nil ++ b = b
37+
(Cons x xs) ++ b = Cons x (xs ++ b)
2838

2939
-- Список без первого элемента
3040
tail :: List a -> List a
31-
tail = undefined
41+
tail Nil = error "List.tail: empty list"
42+
tail (Cons x xs) = xs
3243

3344
-- Список без последнего элемента
3445
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)
3649

3750
-- Первый элемент
3851
head :: List a -> a
39-
head = undefined
52+
head Nil = error "List.head: empty list"
53+
head (Cons x xs) = x
4054

4155
-- Последний элемент
4256
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
4460

4561
-- n первых элементов списка
4662
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
4866

4967
-- Список без n первых элементов
5068
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
5272

5373
-- Оставить в списке только элементы удовлетворяющие p
5474
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)
5677

5778
-- Обобщённая версия. Вместо "выбросить/оставить" p
5879
-- говорит "выбросить/оставить b".
5980
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
6185

6286
-- Копировать из списка в результат до первого нарушения предиката
6387
-- takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]
6488
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
6691

6792
-- Не копировать из списка в результат до первого нарушения предиката,
6893
-- после чего скопировать все элементы, включая первый нарушивший
6994
-- dropWhile (< 3) [1,2,3,4,1,2,3,4] == [3,4,1,2,3,4]
7095
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
7298

7399
-- Разбить список в пару (найбольший префикс удовлетворяющий p, всё остальное)
74100
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)
76106

77-
-- Разбить список по предикату на (takeWhile p xs, dropWhile p xs),
107+
-- Разбить список по предикату на (takeWhile (not . p) xs, dropWhile (not . p) xs),
78108
-- но эффективнее
79109
break :: (a -> Bool) -> List a -> Pair (List a) (List a)
80-
break = undefined
110+
break p = span (not . p)
81111

82112
-- n-ый элемент списка (считая с нуля)
83113
(!!) :: List a -> Nat -> a
84114
Nil !! n = error "!!: empty list"
85-
l !! n = undefined
115+
(Cons x xs) !! Zero = x
116+
(Cons x xs) !! (Succ n) = xs !! n
86117

87118
-- Список задом на перёд
88119
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+
90125

91126
-- (*) Все подсписки данного списка
92127
subsequences :: List a -> List (List a)
93128
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))
95134

96135
-- (*) Все перестановки элементов данного списка
97136
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+
99143

100144
-- (*) Если можете. Все перестановки элементов данного списка
101145
-- другим способом
102146
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)
104158

105159
-- Повторяет элемент бесконечное число раз
106160
repeat :: a -> List a
107-
repeat = undefined
161+
repeat x = Cons x $ repeat x
108162

109163
-- Левая свёртка
110164
-- порождает такое дерево вычислений:
@@ -118,12 +172,14 @@ repeat = undefined
118172
-- / \
119173
-- z l!!0
120174
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
122177

123178
-- Тот же foldl, но в списке оказываются все промежуточные результаты
124179
-- last (scanl f z xs) == foldl f z xs
125180
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)
127183

128184
-- Правая свёртка
129185
-- порождает такое дерево вычислений:
@@ -138,32 +194,39 @@ scanl = undefined
138194
-- z
139195
--
140196
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
142199

143200
-- Аналогично
144201
-- 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
147206

148207
-- Должно завершаться за конечное время
149208
finiteTimeTest = take (Succ $ Succ $ Succ $ Succ Zero) $ foldr (Cons) Nil $ repeat Zero
150209

151210
-- Применяет f к каждому элементу списка
152211
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
154214

155215
-- Склеивает список списков в список
156216
concat :: List (List a) -> List a
157-
concat = undefined
217+
concat = foldr (++) Nil
158218

159219
-- Эквивалент (concat . map), но эффективнее
160220
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
162223

163224
-- Сплющить два списка в список пар длинны min (length a, length b)
164225
zip :: List a -> List b -> List (Pair a b)
165-
zip a b = undefined
226+
zip = zipWith Pair
166227

167228
-- Аналогично, но плющить при помощи функции, а не конструктором Pair
168229
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

ITMOPrelude/Primitive.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ data Maybe a = Nothing | Just a deriving (Show,Read)
4646
-- Частый частный случай, изоморфно Either Unit Unit
4747
data Bool = False | True deriving (Show,Read)
4848

49+
not True = False
50+
not False = True
51+
4952
-- Следует отметить, что встроенный if с этим Bool использовать нельзя,
5053
-- зато case всегда работает.
5154

@@ -181,9 +184,9 @@ n .-. m = n .+. (intNeg m)
181184

182185
infixl 7 .*.
183186
(.*.) :: Int -> Int -> Int
187+
(Positive Zero) .*. (NegativeMinusOne _) = Positive Zero
184188
(Positive n) .*. (Positive m) = Positive $ n *. m
185189
(NegativeMinusOne n) .*. (NegativeMinusOne m) = Positive $ (Succ n) *. (Succ m)
186-
(Positive Zero) .*. (NegativeMinusOne _) = Positive Zero
187190
(Positive n) .*. (NegativeMinusOne m) = NegativeMinusOne $ (n *. (Succ m)) -. natOne
188191
n@(NegativeMinusOne _) .*. m@(Positive _) = m .*. n
189192

0 commit comments

Comments
 (0)