on dependabot/npm_and_yarn/reveal.js/engine.io-3.6.1
help
sign in
3author: Ilya Kostyuchenko
6# Функциональное программирование
11```{ .haskell .fragment }
12data CircleType = Circle Double Double Double
13data RectangleType = Rectangle Double Double Double Double
16 CircleShape CircleType | RectangleShape RectangleType
19```{.haskell .fragment}
20shape = CircleShape (Circle 0 0 2)
21otherShape = RectangleShape (Rectangle 1 2 3 4)
28Имя, Фамилия, Отчество, Адрес, Почта, Возраст
30```{ .haskell .fragment }
32 Person String String String String String Natural
35{height=200px .fragment}
43 Person String String String String String Natural
46```{ .haskell .fragment }
47firstName :: Person -> String
48firstName (Person name _ _ _ _ _) = name
50```{ .haskell .fragment }
51setFirstName :: String -> Person -> Person
54 (Person _ lName mName address email age)
55 = Person newName lName mName address email age
58```{ .haskell .fragment }
59lastName :: Person -> String
60lastName (Person _ lName _ _ _ _) = lName
61setLastName :: String -> Person -> Person
64 (Person fName _ mName address email age)
65 = Person fName newLastName mName address email age
71middleName :: Person -> String
72middleName (Person _ _ mName _ _ _) = mName
73setMiddleName :: String -> Person -> Person
76 (Person fName lName _ address email age)
77 = Person fName lName newMiddleName address email age
80{height=200px .fragment}
82[А что если структуры еще больше?]{.fragment}
88```{ .haskell .fragment }
91 { firstName :: String,
100```{ .haskell .fragment }
101-- Автоматически генерируются компилятором!
102firstName :: Person -> String
103lastName :: Person -> String
107```{ .haskell .fragment }
108setFirstName :: String -> Person -> String
109setFirstName newName person = person {firstName = newName}
110-- Делает копию, заменяя одно (или нескеолько) поле.
111-- (То есть функции set... не нужны)
120> Полиморфизм -- одну реализацию можно применять к разным типам.
128```{ .haskell .fragment }
129map :: (a -> b) -> [a] -> [b]
132```{ .haskell .fragment }
133filter :: (a -> Bool) -> [a] -> [a]
136[Problem: сама функция с `a` и `b` делать ничего не может -- она про них ничего не знает.]{.fragment}
141quicksort :: [Int] -> [Int]
144```{ .haskell .fragment }
145quicksort :: [a] -> [a]
148[Откуда `sort` узнает что такое `a` и как их сравнивать?]{.fragment}
156Самое близкое -- интрефейс.
158> Описывает свойства, которыми должен обладать объект
164 (==) :: a -> a -> Bool
167[`a` относится к классу `Eq` если существует такая функция `(==) :: a -> a -> Bool`]{.fragment}
173 (==) :: a -> a -> Bool
176```{ .fragment .haskell }
177data PersonType = Person String Int
180```{ .fragment .haskell }
181instance Eq PersonType where
182 (Person name1 age1) == (Person name2 age2) =
183 name1 == name2 && age1 == age2
186[instance -- "удовлетворяет", а не "экземпляр".]{ .fragment }
192```{ .haskell .fragment }
193notEqual :: a -> a -> Bool
196```{ .haskell .fragment }
197notEqual :: Eq a => a -> a -> Bool
198notEqual a b = not (a == b)
205class Eq a => Ord a where
206 (<=) :: a -> a -> Bool
209[`a` относится к классу `Ord` если он относится к классу `Ord` и существует такая функция `(<=) :: a -> a -> Bool`]{.fragment}
214class Eq a => Ord a where
215 (<=) :: a -> a -> Bool
219data PersonType = Person String Int
222```{ .fragment .haskell }
223instance Eq PersonType where
224 (Person name1 age1) == (Person name2 age2) =
225 name1 == name2 && age1 == age2
228```{ .fragment .haskell }
229instance Ord PersonType where
230 (Person name1 age1) <= (Person name2 age2) =
231 name1 <= name2 && age1 <= age2
238```{ .haskell .fragment }
239(>) :: Ord a => a -> a -> Bool
243```{ .haskell .fragment }
244(>=) :: Ord a => a -> a -> Bool
245a >= b = a > b || a == b
248[Тут мы можем использовать `>` на типах `a` потому что внутри функции уже есть определение `Ord a`.]{.fragment}
252`notEqual` в стандартной библиотеке определен как `/=`.
257max :: Ord a => a -> a -> a
258max a b = if a > b then a else b
261[Из-за сильной системы типов гарантируется что функция вернет один из своих аргументов.]{.fragment}
267```{ .haskell .fragment }
268data Maybe a = Just a | Nothing
270```{ .haskell .fragment }
271isJust :: Maybe a -> Bool
274```{ .haskell .fragment }
275isJust Nothing = False
276isJust (Just _) = True
279```{ .haskell .fragment }
285[Просто возможность делать pattern matching где угодно, а не только в аргументах функций.]{ .fragment }
290maximum :: Ord a => [a] -> Maybe a
293```{ .haskell .fragment }
294max :: Ord a => a -> a -> a
297```{ .haskell .fragment }
298maximum :: Ord a => [a] -> Maybe a
300maximum (x : xs) = case maximum xs of
302 Just y -> Just (max x y)
307## Полиморфные инстансы
309```{ .haskell .fragment }
310instance Ord (Maybe a)
313```{ .haskell .fragment }
317```{ .haskell .fragment }
318instance Eq a => Eq (Maybe a) where
319 (==) Nothing Nothing = True
320 (==) (Just a) (Just b) = a == b
324```{ .haskell .fragment }
325instance Ord a => Ord (Maybe a) where
326 -- Потому что мы хотим чтобы Nothing был меньше всех
328 (Just a) <= (Just b) = a <= b
329 (Just _) <= Nothing = False
336```{ .haskell .fragment }
337maximum :: Ord a => [a] -> Maybe a
339maximum (x : xs) = case maximum xs of
341 Just y -> Just (max x y)
344```{ .haskell .fragment }
345maximum :: Ord a => [a] -> Maybe a
347maximum (x : xs) = max (Just x) (maximum xs)
354> Моноид -- полугруппа с нейтральным элементом
360```{ .haskell .fragment }
361class Semigroup s where
365```{ .haskell .fragment }
366instance Semigroup [x] where
367 a <> b = a ++ b -- конкатенация списков
370## [Моноид]{.fragment}
372```{ .haskell .fragment }
373class Semigroup s => Monoid s where
377```{ .haskell .fragment }
378instance Monoid [x] where
384"Схлопывает" список моноидов.
387fold :: Monoid m => [m] -> m
390```{ .haskell .fragment }
392fold (x : xs) = x <> fold xs
395```{ .haskell .fragment }
396fold [[1, 3, 5], [42, 69]]
403fold :: Monoid m => [m] -> m
405fold (x : xs) = x <> fold xs
408```{ .haskell .fragment }
410-- Что должно произойти?
415У целых чисел нет одного определения моноида.
417[Но мы можем определить свои типы!]{.fragment}
419```{ .haskell .fragment }
420data Sum = Sum { unSum :: Int }
423```{ .haskell .fragment }
424instance Semigroup Sum where
425 (Sum a) <> (Sum b) = Sum (a + b)
428```{ .haskell .fragment }
429instance Monoid Sum where
433```{ .haskell .fragment }
434map :: (a -> b) -> [a] -> [b]
437```{ .haskell .fragment }
442```{ .haskell .fragment }
443(unSum . fold . map Sum) [1, 2, 3]
451```{ .haskell .fragment }
456```{ .haskell .fragment }
457data Foo = Bar Int Int String
461```{ .haskell .fragment }
462show (Bar 1 2 "hello")
466```{ .haskell .fragment }
467data Foo = Bar Int Int String
468 deriving (Show, Eq, Ord)
471```{ .haskell .fragment }
472Bar 3 10 "hello" == Bar 3 10 "hello"
474Bar 3 10 "hello" == Bar 3 10 "oh no"
478```{ .haskell .fragment }
479Bar 3 10 "hello" < Bar 4 -1000 "oh no"
488[Тип можно обозвать как-то по-другому чтобы код было удобнее читать.]{.fragment}
490```{ .haskell .fragment }
494```{ .haskell .fragment }
499```{ .haskell .fragment }
500data Person = Person Name Age
503[Буквально эквивалентно тому чтобы сделать find and replace по коду.]{.fragment}
508scream :: String -> String
512```{ .haskell .fragment }
516```{ .haskell .fragment }
526[В функцию `capitalize` можно передать константу типа `Name` потому что `String` и `Name` это одно и то же.]{.fragment}
532`type` -- просто обозвали по-другому
537fold :: Monoid m => [m] -> m
539fold (x : xs) = x <> fold xs
542```{ .haskell .fragment }
543fold ["Hello", "World"]
547-- type String = [Char]
557TreeMap<String, Integer> m = new TreeMap();
563```{ .java .fragment }
568```{ .java .fragment }
573```{ .java .fragment }
579[Неявный контекст ошибки ВЕЗДЕ.]{.fragment}
585 Pair<V, Boolean> get(K key) {
589```{ .java .fragment }
590Pair<Integer, Boolean> result = m.get("one");
592if (result.second()) {
600```{ .java .fragment }
601Pair<Integer, Boolean> result = m.get("five");
603if (result.second()) {
615 V get(K key) throws NoElementException {
619```{ .java .fragment }
621 print(m.get("five"));
622} catch (NoElementException e) {
635```{ .java .fragment }
637 Optional<V> get(K key) {
645m = fromList [("one", 1), ("two", 2), ("three", 3)]
648```{ .haskell .fragment }
649data Maybe a = Just a | Nothing
652```{ .haskell .fragment }
653lookup :: k -> Map k v -> Maybe v
656```{ .haskell .fragment }
661```{ .haskell .fragment }
666```{ .haskell .fragment }
667case lookup "one" m of
675data Either a b = Left a | Right b
678```{ .haskell .fragment }
679lookup :: k -> Map k v -> Either MapError v
682```{ .haskell .fragment }
683makePayment :: Card -> Amount -> Either PaymentError Card
686```{ .haskell .fragment }
687makePayment card amount =
688 if balance card >= amount
689 then Right (withdraw amount card)
690 else Left InsufficientFunds
696-- Обновляет аккаунт пользователя новой информацией о карте
697updateAccount :: Account -> Card -> Account
700```{ .haskell .fragment }
701makePayment :: Card -> Amount -> Either PaymentError Card
704```{ .haskell .fragment }
705card = creditCard account
707newAcccount :: Either PaymentError Account
709 updateAccount account (makePayment card (RUB 150))
712```{ .haskell .fragment }
714 updateAccount account (makePayment card (RUB 150))
715-- (Card -> Account) (Either PaymentError Card)
718```{ .haskell .fragment }
720 case makePayment card (RUB 150) of
722 Right c -> updateAccount account c
729 updateAccount account (makePayment card (RUB 150))
730-- (Card -> Account) (Either PaymentError Card)
733```{ .haskell .fragment }
735 magic (updateAccount account) (makePayment card (RUB 150))
736-- | (Card -> Account) (Either PaymentError Card)
739-- -> (Either PaymentError Card
740-- -> Either PaymentError Account)
747```{ .haskell .fragment }
748map :: (a -> b) -> [a] -> [b]
751```{ .haskell .fragment }
752map :: (a -> b) -> ([a] -> [b])
755```{ .haskell .fragment }
758 ( (Either PaymentError) Card ->
759 (Either PaymentError) Account
763```{ .haskell .fragment }
764type F = Either PaymentError
767```{ .haskell .fragment }
768magic :: (Card -> Account) -> (F Card -> F Account)
774magic :: (Card -> Account) -> (F Card -> F Account)
777[А мы можем обобщить `F`?]{.fragment}
779```{ .haskell .fragment }
783 (f Card -> f Account)
790{width=450 .fragment}
792{width=450 .fragment}
798 fmap :: (a -> b) -> f a -> f b
801```{ .haskell .fragment }
802class Functor [] where
803 fmap :: (a -> b) -> [a] -> [b]
805 fmap f (x : xs) = f x : fmap f xs
808```{ .haskell .fragment }
809class Functor Maybe where
810 fmap :: (a -> b) -> Maybe a -> Maybe b
811 fmap _ Nothing = Nothing
812 fmap f (Just x) = Just (f x)
815```{ .haskell .fragment }
816class Functor (Either e) where
817 fmap :: (a -> b) -> Either e a -> Either e b
818 fmap _ (Left e) = Left e
819 fmap f (Right x) = Right (f x)
825updateAccount :: Account -> Card -> Account
826makePayment :: Card -> Amount -> Either PaymentError Card
828newAcccount :: Either PaymentError Account
830 fmap (updateAccount account) (makePayment card (RUB 150))
837 fmap :: (a -> b) -> f a -> f b
840```{ .haskell .fragment }
841class Functor (x ->) where
842 fmap :: (a -> b) -> (x -> a) -> (x -> b)
843 fmap (f :: a -> b) (g :: x -> a) = \(u :: x) -> f (g u)
846```{ .haskell .fragment }
847 fmap (f :: a -> b) (g :: x -> a) = f . g
850```{ .haskell .fragment }
857## [= Alternative!]{.fragment}
860```{ .haskell .fragment }
866```{ .haskell .fragment }
867foo :: f a -> f a -> f a
870```{ .haskell .fragment }
871class Functor f => Alternative f where
872 (<|>) :: f a -> f a -> f a
879class Functor f => Alternative f where
880 (<|>) :: f a -> f a -> f a
884```{ .haskell .fragment }
885instance Alternative Maybe where
886 (Just x) <|> _ = Just x
892```{ .haskell .fragment }
897```{ .haskell .fragment }
905instance Monoid e => Alternative (Either e) where
906 (Right x) <|> _ = Right x
911```{ .haskell .fragment }
912Left "oh no" <|> Right 8
916```{ .haskell .fragment }
921```{ .haskell .fragment }
922makePayment :: Card -> Amount -> Either PaymentError Card
925```{ .haskell .fragment }
926makePayment card1 (Rub 150) <|> makePayment card2 (Rub 150)
932instance Alternative [] where
937```{ .haskell .fragment }
938class Applicative f => Alternative f where ...
941```{ .haskell .fragment }
942class Functor f => Applicative f where
947```{ .haskell .fragment }
948mult :: Alternative f => Int -> f Int
956 then pure m <|> mult (n `div` m)
967```{ .haskell .fragment }
972```{ .haskell .fragment }
977```{ .haskell .fragment }
985import Control.Applicative
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list