-- 1. Functor -- 1.1. -- Functor - это всё, что может "содержать" в себе значение, и через что можно делать fmap (обобщение map). Например, Maybe, List и IO имеют typeclass Functor. Functor - это typeclass для type constructor'ов. Пусть f - это type constructor, который имеет typeclass Functor. Тогда f a - это тип, значения которого могут "содержать" значения типа a. Пусть x - это "контейнер" типа f a, то есть он "содержит" значение типа a. Пусть g - это функция типа a -> b. Тогда fmap g x - это то, что получится, если "протащить" функцию g внутрь "контейнера" x. fmap g x имеет тип f b, то есть это "контейнер", содержащий значение типа b -- 1.2. class Functor f where fmap :: (a -> b) -> f a -> f b -- 1.3. Laws fmap id = id fmap (f . g) = fmap f . fmap g -- 1.4. Maybe instance Functor Maybe where fmap f (Just x) = Just (f x) fmap f Nothing = Nothing -- 1.5. [] instance Functor [] where fmap = map -- 1.6. IO (в книге утверждается, что оно так определено) instance Functor IO where fmap f action = do result <- action return (f action) -- 2. Applicative -- 2.1. -- Applicative - это то, что может "содержать" значение, как и Functor, но также позволяет применять функцию в "коробке" к значению в "коробке". pure - это функция, которая "заворачивает" значение в "коробку". (<*>) - это функция, которая применяет функцию в "коробке" к значению в "коробке" -- 2.2. class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b -- 2.3. Laws pure f <*> x = fmap f x pure id <*> v = v pure (.) <*> u <*> v <*> w = u <*> (v <*> w) pure f <*> pure x = pure (f x) u <*> pure y = pure ($ y) <*> u -- 2.4. Maybe instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just f) <*> something = fmap f something -- 2.4.1 ghci> pure (+) <*> Just 3 <*> Just 5 Just 8 ghci> pure (+) <*> Just 3 <*> Nothing Nothing ghci> pure (+) <*> Nothing <*> Just 5 Nothing -- Поэтому есть такая функция: (<$>) :: (Functor f) => (a -> b) -> f a -> f b f <$> x = fmap f x -- f <$> x <*> y, fmap f x <*> y и pure f <*> x <*> y - это одно и то же -- 2.5. List instance Applicative [] where pure x = [x] fs <*> xs = [f x | f <- fs, x <- xs] -- то есть каждый с каждым -- 2.6. IO (в книге утверждается, что оно так определено) instance Applicative IO where pure = return a <*> b = do f <- a x <- b return (f x) -- 2.7. liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c liftA2 f a b = f <$> a <*> b ghci> fmap (\x -> [x]) (Just 4) Just [4] ghci> liftA2 (:) (Just 3) (Just [4]) Just [3,4] ghci> (:) <$> Just 3 <*> Just [4] Just [3,4] ghci> (:) <$> Just 2 <*> Just [3,4] Just [2,3,4] -- Итак, если есть несколько "контейнеров", то можно сделать "контейнер" со списком. Давайте сделаем функцию, которая будет брать список "контейнеров" и превращать его в "контейнер" со списком: sequenceA :: (Applicative f) => [f a] -> f [a] sequenceA [] = pure [] sequenceA (x:xs) = (:) <$> x <*> sequenceA xs -- это "наша" функция, в отличие от предыдущих ghci> sequenceA [Just 3, Just 2, Just 1] Just [3,2,1] ghci> sequenceA [Just 3, Nothing, Just 1] Nothing -- для IO sequenceA - это то же, что и sequence -- 2.8. Объяснение, почему в sequence IO actions действительно выполняются по порядку * sequence [x, y] * sequence x:(y:[]) * (:) <$> x <*> ((:) <$> y <*> pure []) * (fmap (:) x) <*> ((fmap (:) y) <*> return []) * do f <- fmap (:) x z <- (fmap (:) y) <*> return [] return (f z) * do f <- fmap (:) x z <- do g <- fmap (:) y t <- return [] return (g t) return (f z) * do f <- fmap (:) x z <- fromHumanLang "IO action, которое возвращает результат y, заключённый в список" return (f z) * Вроде понял -- 3. Monad -- 3.1. -- Хочется иметь такую функцию: (>>=) :: (Monad m) => m a -> (a -> m b) -> m b -- Это почти то же самое, что и fmap и <*> с той разницей, что: -- a. "Протаскиваем" функцию вида a -> m b, а не a -> b -- b. Аргументы в другом порядке -- Typeclass | Metafunction | Function type | "Container" cocrete type | Result type -- Functor | fmap | a -> b | f a | f b -- Applicative | (<*>) | f (a -> b) | f a | f b -- Monad | (>>=) | a -> m b | m a | m b -- Это нужно, когда у нас есть функция (функция вида a -> m b), которая может сработать или не сработать (например, если m - это Maybe) -- 3.2. class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b x >> y = x >>= \_ -> y fail :: String -> m a fail msg = error msg -- 3.2.1, Now go read the section "Walk the line"