# Монады (и другие функциональные структуры)

Монады одни из самых страшных тем для новичков в Haskell. Но как и большинство идей, они перестают быть страшными с приходом понимания. Есть множество пособий и множество определений, что такое на самом деле монады и как это объяснить людям. Эта серия - попытка облегчить это больное место для тех кто начинает изучать Haskell. Мы будем делать всё с базовых понятий, начнем с функторов и аппликативных функторов чтобы иметь представление как абстрактные структуры работают в Haskell. Затем потрогаем монады и взглянем на самые распространенные.

# Функторы

Добро пожаловать в нашу серию статей. Монады одна из тех идей, которая кажется причиной множества страхов и мучений среди множества людей пробоющих Haskell. Цель этой серии показать, что это не страшная и не сложная идея, и может быть легко разобрана делая определенные шаги.

# Простой пример.
Есть простой пример с которого мы начнем наш путь. Этот код превращает входную строку типа `John Doe 24` в кортеж. Мы хотим учитывать все входные варианты, поэтому результатом будет `Maybe`.
```haskell
tupleFromInputString :: String -> Maybe (String, String, Int)
tupleFromInputString input = if length stringComponents /= 3
  then Nothing
  else Just (stringComponents !! 0, stringComponents !! 1, age)
  where 
    stringComponents = words input
    age = (read (stringComponents !! 2) :: Int)
```
Эта простая функция принимает строку и преобразует её в параметры для имени, фамилии и возраста. Предположим у нас есть другая часть программы использующая тип данных для отображение человека вместо кортежа. Мы захотим написать функцию преобразователь между этими двумя видами. Мы так же хотим учитывать ситуацию  невозможности этого преобразования. Поэтому есть другая функция, которая обработает этот случай.
```haskell
data Person = Person {
  firstName :: String,
  lastName :: String,
  age :: Int
}

personFromTuple :: (String, String, Int) -> Person
personFromTuple (fName, lName, age) = Person fName lName age

convertTuple :: Maybe (String, String, Int) -> Maybe Person
convertTuple Nothing = Nothing
convertTuple (Just t) = Just (personFromTuple t)
```
# Изменение формата
Но, представьте, наша оригинальная программа меняется в части чтения всего списка имен:
```haskell
listFromInputString :: String -> [(String, String, Int)]
listFromInputString contents = mapMaybe tupleFromInputString (lines contents)

tupleFromInputString :: String -> Maybe (String, String, Int)
...
```
Теперь если мы передаем результат коду используя `Person` мы должны изменить тип функции `convertTuple`. Она будет иметь паралельную структуру. `Maybe` и `List` оба действуют как хранитель других значений. Иногда, нас не заботит во что обернуты значения. Нам просто хочется преобразовать что-то лежащее под существующим значением. и затем запустим новое значение в той же обертке. 

# Введение в функторы
С этой идеи мы можем начать разбирать функторы. Первое и главное: Функтор это класс типа в Haskell. Для типов которые являются экземплярами функторных классов типа, они должны реализовывать простую функцию: `fmap`.
```haskell
fmap :: (a -> b) -> f a -> f b
```
Функция `fmap` принимает два ввода. Первый - требует функцию для вдух типов данных. Второй параметр - хранилище первоо типа. Вывод - хранилище второго типа. Теперь взглянем на несколько различных экземпляров функторов для знакомых типов. Для списков, `fmap` просто определяется как базовая функция `map`:
```haskell
instance Functor [] where
  fmap = map
```
На самом деле, `fmap` это обобщение соответствия. Например, тип данных `Map` так же функтор. Он использует свою собственную функцию `map` для `fmap`. Функторы просто берут эту идею преобразования всех ниже лежащих значений и применяют их к другим типам. С этим, давайте взглянем на `Maybe` как на функтор:
```haskell
instance Functor Maybe where
  fmap _ Nothing = Nothing
  fmap f (Just a) = Just (f a)
```
Выглядит довольно похоже на нашу функцию `convertTuple`. Если у нас нет значения на первом месте, тогда результат `Nothing`. Если имеется значение, тогда просто применяется функция к значение и превращает её в `Just`. Тип данных `Either` может быть типом `Maybe` с дополнительной информацией по какой причине. Он имеет схожее поведение:
```haskell
instance Functor (Either a) where
    fmap _ (Left x) = Left x
    fmap f (Right y) = Right (f y)
```
Отметим, что параметр первого типа этого объекта исправлен. Только второй параметр значения `Either` изменен с помощью `fmap`. Основываясь на этих примерах, мы можем увидеть как переписать `convertTuple` обощеннее:
```haskell
convertTupleFunctor :: Functor f => f (String, String, Int) -> f Person
convertTupleFunctor = fmap personFromTuple
```

# Делаем свой функтор
Мы так же можем взять свой собственный тип и определить экмзепляр Функтора. Предположим у нас есть следующий тип данных, отражаюищй папку должностных лиц правительства на местах. Зададим его типом a. Это значит, что мы позволяем различным папкам использовать различные представления должностных лиц. 
```haskell
data GovDirectory a = GovDirectory {
  mayor :: a,
  interimMayor :: Maybe a,
  cabinet :: Map String a,
  councilMembers :: [a]
}
```
Одна часть нашего приложения может отражать людей с помощь кортежей. Это будет тип `GovDirectory(String, String, Int)`. В то время, как другая часть может использовать тип `GovDirectory Person`. Мы можем определить следующий экземпляр функтора для `GovDirectory` определив `fmap`. Так как наш тип лежащий внутри в вцелом является функтором, это позволяет просто вызывать `fmap` для полей.
```haskell
instance Functor GovDirectory where
  fmap f oldDirectory = GovDirectory {
    mayor = f (mayor oldDirectory),
    interimMayor = fmap f (interimMayor oldDirectory),
    cabinet = fmap f (cabinet oldDirectory),
    councilMembers = fmap f (councilMembers oldDirectory)
  }
```
Так же можно использовать инфиксный оператор `<$>` в качестве синонима `fmap`. Чтобы описать всё гораздо проще:
```haskell
instance Functor GovDirectory where
  fmap f oldDirectory = GovDirectory {
    mayor = f (mayor oldDirectory),
    interimMayor = f <$> interimMayor oldDirectory,
    cabinet = f <$> cabinet oldDirectory,
    councilMembers = f <$> councilMembers oldDirectory
  }
```
Теперь у нас есть свой функтор, преобразование типов данных внутри нашей папки теперь проще. Мы можем просто использовать `fmap` объединив с нашей функцией преобразования, `personFromTuple`:
```haskell
oldDirectory :: GovDirectory (String, String, Int)
oldDirectory = GovDirectory
  ("John", "Doe", 46)
  Nothing
  (M.fromList 
    [ ("Treasurer", ("Timothy", "Houston", 51))
    , ("Historian", ("Bill", "Jefferson", 42))
    , ("Sheriff", ("Susan", "Harrison", 49))
    ])
  ([("Sharon", "Stevens", 38), ("Christine", "Washington", 47)])

newDirectory :: GovDirectory Person
newDirectory = personFromTuple <$> oldDirectory
```
# Выводы
Теперь вы знаете о функторах, нужно время, чтобы понять эти типы структур. Двигаемся к части 2, где мы обсудим применение функторов.

# Аппликативные функторы

Добро пожаловать во вторую часть серии о монадах и других функциональных структур. Мы продолжим готовить собирать нашу базу изучая идеи апликативных функторов. Если вы всё еще не  имеете твердое понимание функторов, пересмотрите первую часть этой серии. Если вы считаете, что уже готовы к монадам, то можете смело переходить к части 3.

В этой части приведенные примеры можно будет опробовать на GHCI. 

# Функторы становятся короткими
В первой части, мы обсудили функтор типа класса. Мы нашли, то что это позволяет нам запустить преобразования данных в зависимости от того, во что обернуты данные. Не важно, являются ли наши данные `List`, `Maybe`, `Either` или даже свой собственный тип, мы можем просто вызывать `fmap`. Однако, что случится когда мы попробуем объединить обернутые данные? Для примера, если мы попробуем произвести эти вычисления с помощью GHCI, мы получим ошибку типа:
```haskell
>> (Just 4) * (Just 5)
>> Nothing * (Just 2)
```
Могут ли функции помочь нам тут? Мы можем исопльзовать `fmap` чтобы обернуть умножение с помощью частичной обертывания `Maybe` значения:
```haskell
>> let f = (*) <$> (Just 4)
>> :t f
f :: Num a => Maybe (a -> a)
>> (*) <$> Nothing
Nothing
```
Это дает частичную функци обернутую в `Maybe`. Но мы до сих пор не может развернуть это и применить к `Just 5` в общем стиле. Поэтому нам нужно обратиться к коду специально для типа `Maybe`:
```haskell
funcMaybe :: Maybe (a -> b) -> Maybe a -> Maybe b
funcMaybe Nothing _ = Nothing
funcMaybe (Just f) val = f <$> val
```
Это очевидно не будет работать с другими типами функторов.

# Приложения в помощь
То что такое апликативные типы классов, говорят две главные функции:
```haskell
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
```
Чистая фнукция принимает какое-то значение и обертывает его в минимальный контекст. Функция `<*>` вызывает последующиее приложение, которое принимает 2 параметра. Первый - принимает функци обернутую в конекст. Второе - обернутое значение. Вывод - результат применения функции к значению, преобразованное в контексте. Экземпляр называется аппликативный функтор так как он позволяет нам применять обернутую функцию. Так как последюущее применение принимает обернутую функцию, мы ычасто начинаем с обертки чего-то чистого или `fmap`. Это будет понятнее на примерах.

Для начала представим перемножение `Maybe` значений. Если мы умножаем на постоянное значение, мы можем использовать функторный подход. Но мы можем так же использовать аппликативный подход обернув постоянную функцию в чистую и затем использовать последовательное применение:
```haskell
>> (4 *) <$> (Just 5)
Just 20
>> (4 *) <$> Nothing
Nothing
>> pure (4 *) <*> (Just 5)
Just 20
>> pure (4 *) <*> Nothing
Nothing
```
Теперь если мы хотим умножить 2 `Maybe` значения, мы начинаем оборачивать простую функцию произведения в чистую. Затем последовательно применяем оба `Maybe` значения:
```haskell
>> pure (*) <*> (Just 4) <*> (Just 5)
Just 20
>> pure (*) <*> Nothing <*> (Just 5)
Nothing
>> pure (*) <*> (Just 4) <*> Nothing
Nothing
```
# Реализация аппликативов 
По этим примерам, мы можем сказать, что экземпляры Аппликативов для `Maybe` реализованны точно, как мы ожидаем. Чистая функция просто оборачивает начение с помощью `Just`. Затем связывает веще вмете, если другие функции или знаения будут `Nothing`, мы просто выводим `Nothing`. В противном случае применяем функцию к значение и переоборачиваем с помощью `Just`.
```haskell
instance Applicative Maybe where
  pure = Just
  (<*>) Nothing _ = Nothing
  (<*>) _ Nothing = Nothing
  (<*>) (Just f) (Just x) = Just (f x)
```
Экземпляр аппликатива для `List` будет немного интереснее. Он может вести себя на так как мы ожидаем. 
```haskell
instance Applicative [] where
  pure a = [a]
  fs <*> xs = [f x | f <- fs, x <- xs]
```
Чистая функция - то что мы ожидаем. Мы принимаем значение и оборачиваем его как одиночку в список. Когда мы связываем операции, мы принимаем `LIST` функций. Мы должны ожидать применения каждой функции к значению в соответствующей позиции. Однако, на самом деле мы применяем функцию из первого списка к каждому значению из второго. Когда у нас олько одна функция, этот резаультат имеет понятноее поведение. Но когда у нас несколько функций, появляется отличие. 
```haskell
>> pure (4 *) <*> [1,2,3]
[4,8,12]
>> [(1+), (5*), (10*)] <*> [1,2,3]
[2,3,4,5,10,15,10,20,30]
```
Тут легко сделать определенные операции, как нахождение попарных результатов двух списков:
```haskell
>> pure (*) <*> [1,2,3] <*> [10,20,30]
[10,20,30,20,40,60,30,60,90]
```
Вы возможно гадаете, как мы сделаем паралельное применение функторов. Например, мы можемт хотеть использовать второй список из примера выше, но иметь результат `[2,10,30]`.  Для этого есть конструкт под названием `Ziplist`, это новый тип вокрут списка, для которого поведение экземпляр аппликатива и предусмотренно.
```haskell
>> import Control.Applicative
>> ZipList [(1+), (5*), (10*)] <*> [5,10,15]
ZipList {getZipList = [6,50,150]}
```
# Выводы
Если все это кажется непонятным, не бойтесь вернуться к части 1 и убедиться, что у вас есть четкое понимание того, что такое функторы. Если вам всё ясно, вы готовы перейти к части 3, где мы наконец испачкаемся монадами. 

Все эти идея гораздно проще понять если попытаться исполнить код из примеров самостоятельно.

# Монады

Добро пожаловать в часть 3 нашей серии абстрактных структур! Мы, наконец, коснемся идеи монад! Множежство людей пытаются изучить монады без попытки заиметь понимания того. как абстрактные структуры типов класса работают. Это главная причина борьбы. Если вы всё еще этого не пониматете, обратитесь к 1 и 2 части этой серии. 

После этой статьи вы будете готовы к тому, чтобы писать свой собственный код Haskell. 

# Букварь монад 
Есть множество инструкций и поисаний монад в интернете. Количество аналогий просто смешно. Но вот мои 5 копеек в определении: Монада - обертка значения или вычисления с определенным контекстом. Монада должна определять  и смысл обернутого значения в контексте и способ объединения вычислений в контексте.

Это определение достатоно широко. Давайте взглянем на конкретный пример, и попробуем понять.

# Классы типы монад
Так же как с функторами и аппликативными функторами, Haskell отражает монады с помощью тип класса. На это есть две функции:
```haskell
class Monad m where
  return :: a -> m a
  (>>=) :: m a -> (a -> m b) -> m b
```
Эти две функции отвечают двум идеям выше. Функция возвращения определяем как обернуть значения в контексте монад. Оператор `>>=`, который мы назовем его функцией "связывания", определяет как объединить две операции с контекстом. Давайте проясним это далее узучив несколько определенным экземпляров монад. 

# Монада Maybe
`Just` как `Maybe` это функтор  и аппликативный функтор, но еще и монада. Чтобы понять смысл монады `Maybe` давайте посмотрим представим код:
```haskell
maybeFunc1 :: String -> Maybe Int
maybeFunc1 "" = Nothing
maybeFunc1 str = Just $ length str

maybeFunc2 :: Int -> Maybe Float
maybeFunc2 i = if i `mod` 2 == 0
  then Nothing
  else Just ((fromIntegral i) * 3.14159)

maybeFunc3 :: Float -> Maybe [Int]
maybeFunc3 f = if f > 15.0
  then Nothing
  else Just [floor f, ceiling f]

runMaybeFuncs :: String -> Maybe [Int]
runMaybeFuncs input = case maybeFunc1 input of
  Nothing -> Nothing
  Just i -> case maybeFunc2 i of
    Nothing -> Nothing
    Just f -> maybeFunc3 f
```
Можно увидеть, что мы начинаем разрабатывать отвратительный треугольный шаблон, в качестве продолжения шаблона соответствия результатов успешного вызова функций. Если мы добавили еще больше функций `Maybe` в него, то всё станет еще хуже. Если мы считаем `Maybe` в качестве монады, мы можем сделать код гораздо чище. Давайте взглянем на то, как Haskell реализует `Maybe` монаду, чтобы понять как это делать.
```haskell
instance Monad Maybe where
  return = Just
  Nothing >>= _ = Nothing
  Just a >>= f = f a
```
Внутри `Maybe` монада проста. Вычисления созначением в `Maybe` могут как пройти, так и не пройти успешно. Мы можем взять любое значение обернуть его в этом контексте вызовом значения `success`. Мы делаем это с помощью конструктора `Just`. Неуспех обозначается с помощью `Nothing`.

Объединим вычисления в контексте проверяя результа первого вычисления. Если успешно, мы берем его значение и передаем во второе вычисление. Если неуспешно, тогда у нас нет значения для передачи дальше. Поэтому результирующее вычисление не будет успешно. Взглянем на то, как мы можем исопльзовать `bind(>>=)` оператор для объединения наших операторов:
```haskell
runMaybeFuncsBind :: String -> Maybe [Int]
runMaybeFuncsBind input = maybeFunc1 input >>= maybeFunc2 >>= maybeFunc3
```

Выглядит гораздо чище! Давайте взглянем почему работают типы. Результат `maybeFunc1` просто `Maybe Int`. Затем оператор `bind(>>=)` позволяет нам взять это `Maybe Int` значение и объединить с `maybeFunc2`, чей тип `Int -> Maybe Float`. Оператор `bind(>>=)` разрешает значение в `Maybe Float`. Затем мы передаем походим образом через оператор `bind(>>=)` в `maybeFunc3` результатом которой является конечный тип: `Maybe [Int]`.

Ваша функции не всегд будут так ясно сочитаться. Тут в силу вступает запись `do`. Код выше можно переписать следующим образом:
```haskell
runMaybeFuncsDo :: String -> Maybe [Int]
runMaybeFuncsDo input = do
  i <- maybeFunc1 input
  f <- maybeFunc2 i
  maybeFunc3 f
```
Оператор `<-` особенный. Он эффективно разворачивает значение с правой стороны монады. Это значит, что значение `i` имеет типа `Int`, даже не смотря на результат `maybeFunc1` как `Maybe Int`. Оператор `bind(>>=)` работает без нашего участия. Если функция возвращает `Nothing`, тогда вся функция `runMaybeFuncs` вернет `Nothing`.

При беглом осмотре, это выглядит гораздо сложнее, чем пример с `bind(>>=)`. Однако, оно дает нам гораздо больше гибкости. Предположим, мы хотим добавить 2 к целому числу перед вызовом `MaybeFunc2`. Это проще сделать с помощью `do` записи, но гораздо сложноее используя связывания. 
```haskell
runMaybeFuncsDo2 :: String -> Maybe [Int]
runMaybeFuncsDo2 input = do
  i <- maybeFunc1 input
  f <- maybeFunc2 (i + 2)
  maybeFunc3 f

-- Not so nice
runMaybeFuncsBind2 :: String -> Maybe [Int]
runMaybeFuncsBind2 input = maybeFunc1 input
  >>= (\i -> maybeFunc2 (i + 2))
  >>= maybeFunc3
```
Преимущества гораздо очевидны если мы хотим использовать множество прошедших результатов при вызове функии. Используя связывания, мы сможем постоянно складывать аргументы в анонимную функцию. 
> Мы никогда не используем `<-` для развернывания последней операции в блоке `do`. 

Наш вызов `maybeFunc3` имеет тип `Maybe [Int]`. Это наш последний тип(не [Int]) поэтому его не нужно разворачивать.

# монада `Either`
Теперь, давайте посмотрим на монаду `Either`, которая очень похожа на монаду `Maybe`. Вот её определение:
```haskell
instance Monad (Either a) where
  return r = Right r
  (Left l) >>= _ = Left l
  (Right r) >>= f = f r
```
Поскольку `Maybe` имеет успех или не успех со значением, монада `Either` прикладывает информацию к неуспеху. `Just` как `Maybe` обертывает значение в его контексте вызова делая его упешным. Монадическое поведение так же объединяет операции завершаясь на первом не успехе. Давайте посмотрим как мы можем использовать это чтобы сделать наш код выше чище. 
```haskell
eitherFunc1 :: String -> Either String Int
eitherFunc1 "" = Left "String cannot be empty!"
eitherFunc1 str = Right $ length str

eitherFunc2 :: Int -> Either String Float
eitherFunc2 i = if i `mod` 2 == 0
  then Left "Length cannot be even!"
  else Right ((fromIntegral i) * 3.14159)

eitherFunc3 :: Float -> Either String [Int]
eitherFunc3 f = if f > 15.0
  then Left "Float is too large!"
  else Right [floor f, ceiling f]

runEitherFuncs :: String -> Either String [Int]
runEitherFuncs input = do
  i <- eitherFunc1 input
  f <- eitherFunc2 i
  eitherFunc3 f
```
Любой не успех просто даст нам значение `Nothing`:
```haskell
>> runMaybeFuncs ""
Nothing
>> runMaybeFuncs "Hi"
Nothing
>> runMaybeFuncs "Hithere"
Nothing
>> runMaybeFuncs "Hit"
Just [9,10]
```
когда мы запустим наш код, мы можем посмотреть на строковый результат ошибки, и она расскажет нам о том, какая функция не смогла произвести вычисления. 
```haskell
>> runMaybeFuncs ""
Left "String cannot be empty!"
>> runMaybeFuncs "Hi"
Left "Length cannot be even!"
>> runMaybeFuncs "Hithere"
Left "Float is too large!"
>> runMaybeFuncs "Hit"
Right [9,10]
```
Заметим, что мы параметризовали монаду `Either` с помощью нашего типа ошибки. Если у нас есть:
```haskell
data CustomError = CustomError

maybeFunc2 :: Either CustomError Float
...
```
Это функция теперь новая монада. Объединения с другими функциями не будет легким. 

# Монада IO
Монада IO, возмоно, самая важная монада в Haskell. Это так же одна из самых сложных монад для понимания начинающих. Её реализация достаточна сложна для обсуждения при первом знакомстве с языком. Поэтому будем учиться по примерам. 

IO монада обертывает вычисления с ледующем случае: "Вычисления могут читать информацию или писать в терминал, файловую систему, ОС или сеть". Если выхотите получить пользовательский ввод, выведите сообщение пользователю, прочитайте информацию  из файла, или сделайте сетевой вызов, для этого понадобиться IO монада. Эти вызовы имеют "сторонние эффекты", мы нне может произвести их из "чистого" Haskell кода.

Важная работа почти любого компьютера это взаимодействие с внешним миром, каким-то образом. На этот случай, корнем всего выполняемого Haskell кода это функция называемая `main`, с типом `IO()`. Поэтому любая программа начинается с `IO` монады. Отсюда вы можете получить любой необходимый ввод, вызвать относительно "чистый" код с помощью ввода, и затем вывести результат каким-то образом. Обратное не работает. Вы не можете взывать внутри `IO` кода, код, как тот, который вы можете вызвать в `Maybe` функции из чистого кода.

Давайте взглянем на простой пример показывающий несколько базовых `IO` функций. Мы будем использовать do-запись для того, чтобы показать схожесть с другими монадами, которые мы уже встречали. Выведем тип каждой `IO` функции для ясности.
```haskell
main :: IO ()
main = do
  -- getLine :: IO String
  input <- getLine
  let uppercased = map Data.Char.toUpper input
  -- print :: String -> IO ()
  print uppercased
```
Каждый раз мы видим строку нашей программы и она имеет тип IO. Так же как мы можем развернуть `i` в примере `maybe` для получения `Int` взамен `Maybe Int`, мы можем использовать `<-`, чтобы развернуть результат `getLine` в качестве `String`. Мы можем затем использовать это значение с помощью строковой функции, и передаавть результат в  функцию `print`.

Это просто эхо-программа. Она читает строку из терминала и затем выводит строку обратно с капсом. Надеюсь она дает вам базовое понимание того как `IO` работает. Мы залезем глубже в детали в следующей паре статей. 

# Выводы
С этой точки, мы должны наконец иметь лучшее понимание того, что такое монады. Но если они не имеют смысла до сих пор, не раздражайтесь! Мне пришлось потратить несколько попыток, прежде чем я смог понять их. Не бойтесь взглянуть еще разок на 1 и 2 части, чтобы освежить Haskell знания. И определенно стоит прочитать еще разок эту статью.

Если же вам всё понятно, вы готовы двигаться к части 4, где вы изучите о `Reader` и `Writer` монадах, что позволит вам привнести возможность использовать некий функционал в Haskell, о котором вы думали, что он не доступен. 

If you've never programmed in Haskell before, hopefully I've convinced you that it's not that scary and you're ready to check it out! Download our Beginners Checklist to learn how to get started.

# Монады Reader и Writer

В части 3 этой серии, мы наконец затронули идею монад. Мы изучили что они такое, и увидели как некоторые общие типы, например `IO` и `Maybe`, работают в качестве монад. В этой части, мы посмотрим на некоторые другие полезные монады. В частности мы рассмотрим монады `Reader` и `Writer`.

# Глобальные переменные(или их нехватка)
В Haskell, наш код в общем "чистый", что значит, что функции могут только взаимодействовать с аргументами переданными им. Смысл в том, чтобы мы не могли имметь глобальных переменных. Мы можем ипеть глобальные выражения, но они фиксируются во время компиляции. Если поведение пользователя может изменить их, нам нужно обернуть их в `IO` монаду, что значит, что мы не можем использовать её в "чистом" коде. 

Представим следующий пример. Мы хотим иметь `Environment` содержащее параметры в качестве глобальных переменных. Однако, мы должны их загрузить через конфигурационный файл или командную строку, что трубует `IO` монаду. 
```haskell
main1 :: IO ()
main1 = do
  env <- loadEnv
  let str = func1 env
  print str

data Environment = Environment
  { param1 :: String
  , param2 :: String
  , param3 :: String
  }

loadEnv :: IO Environment
loadEnv = ...

func1 :: Environment -> String
func1 env = "Result: " ++ (show (func2 env))

func2 :: Environment -> Int
func2 env = 2 + floor (func3 env)

func3 :: Environment -> Float
func3 env = (fromIntegral $ l1 + l2 + l3) * 2.1
  where
    l1 = length (param1 env)
    l2 = length (param2 env) * 2
    l3 = length (param3 env) * 3
```

Функция на самом деле используется `func3`. Однако `func3` чистая функцияю. Это значит, она не может вызывать напрямую `loadenv`, так как она не "чистая" функция. Это значит, что окружение должно быть передано через переменную в другую функцию, чтобы можно было передать её в функцию `func3`. В языке с глобальными переменными, мы должны сохранить `env` в качестве глобальной переменой в `main`. Функция `func3` должна иметь доступ напрямую. Не нужно иметь парметра для `func1` и `func2`. В больших программах эта передача переменных может устроить головную боль.

# Решение READER
Монада `Reader` решает эту проблему. Она создает глобальное только для чтения значение определенного типа. Все функции внутри монады могут прочитать "тип". Давайте взглянем на то как монада `Reader` меняет форму нашего кода. Наши функции больше не трубуют `Environment`в качесте обязательного параметра, так как они могут получить доступ к ней через монаду. 
```haskell
main :: IO ()
main = do
  env <- loadEnv
  let str = runReader func1' env
  print str

func1' :: Reader Environment String
func1' = do
  res <- func2'
  return ("Result: " ++ show res)

func2' :: Reader Environment Int
func2' = do
  env <- ask
  let res3 = func3 env
  return (2 + floor res3)

-- as above
func3 :: Environment -> Float
...
```
Функция `ask` развертывает окружение для того, чтобы мы могли его исопльзовать. Привязывание действий к моанадам позволяет нам связать различные `Reader` действия. Для того, чтобы вызвать действие чтения из чистого кода, нужно вызвать `runReader` функцию и подать окружение в качестве параметра. Все функции внутри действия будут обращаться как к глобальной переменной. 

Код выше так же вводит важное понятие. Каждый раз, когда вы вводите понятие монада "X", всегда есть соответстующая функция "runX", которая говорит вам как запустить операции над монадой из чистого контекста(IO исключение). Эта функция будет часто требоваться при определенном вводе, так же как и сами вычисления. Затем оно будет производить вывод этим самых вычислений. В этом случае `Reader`, у нас есть `runReader` функция. Она требует значение, которое мы будем читать, и сами вычисления `Reader`. 
```haskell
runReader :: Reader r a -> r -> a
```
Может быть не похоже, что нам многое удалось, но наш код более понятен теперь. Мы сохранили `func3`, так как она есть. Она имеет смысл, чтобы описать её в качестве переменной из `Environment` с помощью функции. Однако, наши другие две функции больше не принимают окружение как обязательные параметры. Они просто существуют в контексте где окружение - глобальная переменная. 

# Сбор значений
Чтобы понять монаду `Winter`, давайте поговорим о проблеме сбора. Предположим у нас есть несколько различных функций. Каждая делает строковые операции, которые чего-то стоят. Мы хотим отслеживать сколько "стоят" все вычисления вместе. Мы можем сделать следующее, для сбора аргументов и слежения за "ценой" которую мы получим. Мы продолжаем передавать собранные переменные вместе с результатом обработки строки.
```haskell
-- Calls func2 if even length, func3 and func4 if odd
func1 :: String -> (Int, String)
func1 input = if length input `mod` 2 == 0
  then func2 (0, input)
  else (i1 + i2, str1 ++ str2)
    where
      (i1, str1) = func3 (0, tail input)
      (i2, str2) = func4 (0, take 1 input)

-- Calls func4 on truncated version
func2 :: (Int, String) -> (Int, String)
func2 (prev, input) = if (length input) > 10
  then func4 (prev + 1, take 9 input)
  else (10, input)

-- Calls func2 on expanded version if a multiple of 3
func3 :: (Int, String) -> (Int, String)
func3 (prev, input) = if (length input) `mod` 3 == 0
  then (prev + f2resI + 3, f2resStr)
  else (prev + 1, tail input)
  where
    (f2resI, f2resStr) = func2 (prev, input ++ "ab")

func4 :: (Int, String) -> (Int, String)
func4 (prev, input) = if (length input) < 10
  then (prev + length input, input ++ input)
  else (prev + 5, take 5 input)
```
Для начала, можно отметить. что структура функции несколько трудно обслуживаемая. Опять, мы передаем дополнительные параметры. В частности, мы отслеживаем общую стоимость, которая показывается для ввода и вывода каждой функции. Монада `Writer`  дает нам простой способ отслеживания значений. Она так же делает легче ля нас отображение стоиомсти для различных типов. Но чтобы понять, как мы должны для начала изучить два типокласса, `Semigroup` и `Monoid`,  которые помогут обощить сбор.

# SEMIGROUPS и MONOIDS
`Semigroup` это любой тип, который мы собираем с помощью "append" оператора. Эта функция использует оператор `<>`. Она объединяет два элемента типа в новый, третий. 
```haskell
class Semigroup a where
  (<>) :: a -> a -> a
```
Для нашего первого простого примера, мы можем думать представить `Int` тип как часть `Semigroup` под операцией сложнения. 
```haskell
instance Semigroup Int where
  a <> b = a + b
```
`Monoid` расширяет определение `Semigroup`, чтобы можно было включить определяющий элемент. Этот элемент называется `mempty`, так как это "empty" элементо сортировки. Отметим, что ограничение `Monoid`  в том, что он уже должен быть `Semigroup`. 
```haskell
class (Semigroup a) => Monoid a where
  mempty :: a
```
Определяющий элемент долен иметь свойства, если мы прибавшяем любой другой элемент `a`, в любом направлении, результатом должен быть `a`. Поэтому результатом `a <> mempty == a` и `mempty <> a == a` всегда должны быть `true`. Мы можем расширить наше определение `Int` для `Semigroup` добавив `0` в качестве определяющего элемента для `Monoid`. 
```haskell
instance Monoid Int where
  memty = 0
```
Мы можем продуктивно использовать `Int` и собирать класс. Функция `mempty` предлагает начальное значение для нешего моноида. Затем с помощью `mappend`,  мы объединяем два значения этого типа в результат. Это довольно легко, сделать экземпляр `Monoid` для `Int`. Наш счетчик начинается с `0`, и мы можем объединить значения для добавления. 

Этот `Int` экземпляр не доступен по умолчания. Это потому, что мы может так же предоставить `Monoid` из `Int` используя перемножение вместо сложения. В этом случае, 1 становится определяющим. 
```haskell
instance Semigroup Int where
  a <> b = a * b

instance Monoid Int where
  mempty = 1
```
В обоих случаях `Int` пример, наша `append` функция суммирующая. Базовая библиотека включет экземпляр `Monoid` для любого типа `List`. Оператор `append` использует оператор прибавления списка `++`, который не суммирующий. В этом случае определяющий элемент это пустой список. 
```haskell
instance Semigroup [a] where
  xs <> ys = xs ++ ys

instance Monoid [a] where
  mempty = []

-- Not commutative!
-- [1, 2] <> [3, 4] == [1, 2, 3, 4]
-- [3, 4] <> [1, 2] == [3, 4, 1, 2]
```
# Использование  WRITER для отслеживания ACCUMULATOR
Как же это помогает нам с проблемой сложения выше?

Монада `Writer` параметризуется с помощью некоторого моноидного типа. Его задача следить за складываемым значением этого типа. Его цель жить в контексте глобальной переменной которую они могут менять. Пока `Reader` дает нам возмоность читать глобальную переменную, но не менять её `Writer` позволяет нам менять значение с помощью сложения, при этом нельзя её читать при вычислении. Мы можем вызвать операцию добавления используя `tell` функцию в цели нашего выражения `Writer`. 
```haskell
tell :: a -> Writer a ()
```
Так же как и с `Reader` и `runReader`, есть `runWriter` фукнция. И выглядит она немного по другому. 
```haskell
runWriter :: Writer w a -> (a, w)
```
Нам не нужно предоставлять дополнительный ввод кроме вычислений для запуска. Но `runWriter` осуществляет 2 вывода!  Первый это результат нашего вычисления. Второй - последнее сложенное значение для `writer`. Мы не предоставили входного значения, так как он автоматически использует `mempty` из `Monoid`!

Давайте изучим как изменить наш код выше, чтобы использовать эту монаду. начнем с `acc2`.
```haskell
acc2' :: String -> Writer Int String
acc2' input = if (length input) > 10
  then do
    tell 1
    acc4' (take 9 input)
  else do
    tell 10
    return input
```
Создаем отдельную ветку по количествую ввходных данных, и для кадой ветки выполняем `do`. Будем использовать `tell` для предоставления соответствующего значения для увеличивания сумматора, и затем двигается к вызову следующей функции, или возвращаем ответ. затем `acc3` и `acc4`. 
```haskell
acc3' :: String -> Writer Int String
acc3' input = if (length input) `mod` 3 == 0
  then do
    tell 3
    acc2' (input ++ "ab")
  else do
    tell 1
    return $ tail input

acc4' :: String -> Writer Int String
acc4' input = if (length input) < 10
  then do
    tell (length input)
    return (input ++ input)
  else do
    tell 5
    return (take 5 input)
```
Наконец, мы не меняем тип подписи нашей оригинальной функци, вместо этого мы используем `runWriter` для вызова помощника, как и положено. 
```haskell
acc1' :: String -> (String, Int)
acc1' input = if length input `mod` 2 == 0
  then runWriter (acc2' input)
  else runWriter $ do
    str1 <- acc3' (tail input)
    str2 <- acc4' (take 1 input)
    return (str1 ++ str2)
```
Отемтим, нам больше не нужно явно отслеживать сумматор. Он не обернут с помощью `writer`  монады. Мы можем увеличить его в любой нашей функии вызвав `tell`. Теперь наш код граздо проще а типы яснее. 

# Выводы
Теперь, зная про `Reader` и  `Writer` монады, пришло время двигаться дальше. Дальше мы обсудим монаду `State`. Эта монада объединяет эти две идеи в `read/write state`, естественно позволяя использовать глобальные переменные на полную. Если эти идеи до сих пор вас смущают, не бойтесь перечитать статью.

# State Монада

В прошлой части, мы изучили монады `Reader` и `Writer`. Они пакакзил, что на самом деле имеем алтернативу глобальным переменным. Нам просто нужно каким-то образом заключить их в определенный тип, это то для чего они нужны. В этой части изучим `State` монаду, которая объединяет некоторую функциональность для обоих идей. 

# Мотивации пост: Крестики-нолики
Для этой части мы воспользуемся простой моделью для игры Крестки-нолики. Главный объект это тип данных `GameState` содержащий несколько важных кусочков информации. Первое и важное, он содержит "доску", и двумерный массив индексов состояния полей(X/0 или пусто). Так же знает чей ход и имеет случайный генератор. 
```haskell
data GameState = GameState
  { board :: A.Array TileIndex TileState
  , currentPlayer :: Player
  , generator :: StdGen
  }

data Player = XPlayer | OPlayer

data TileState = Empty | HasX | HasO
  deriving Eq

type TileIndex = (Int, Int)
```
Давай взглянем на то, как некоторые из функций нашей игры будут работать. Например нужно придумать функцию для случайного выбора хода. Она долна выводить `TileIndex` и изменять генератор нашей игры. Затем основываясь на нем делаем шаг и передаем ход другому игроку. Другими словами, у нас есть операции которые зависят от текущего состояния игры, но так же обновляет это состояние. 

# THE STATE MONAD
This is exactly the situation the State monad deals with. The State monad wraps computations in the context of reading and modifying a global state object. This context chains two operations together in an intuitive way. First, it determines what the state should be after the first operation. Then, it resolves the second operation with the new state.

It is parameterized by a single type parameter s, the state type in use. So just like the Reader has a single type we read from, the State has a single type we can both read from and write to. There are two primary actions we can take within the State monad: get and put. The first retrieves the state, the second modifies it by replacing it with a new object. Typically though, this new object will be similar to the original:
```haskell
-- Retrieves the state, like Reader.ask
get :: State s s

-- Overwrites the existing state
put :: s -> State s ()
```
There is also a runState function, similar to runReader and runWriter. Like the Reader monad, we must provide an initial state, in addition to the computation to run. But then like the writer, it produces two outputs: the result of our computation AND the final state:
```haskell
runState :: s -> State s a -> (a, s)
```
If we wish to discard either the final state or the computation's result, we can use evalState and execState, respectively:
```haskell
evalState :: State s a -> s -> a

execState :: State s a -> s -> s
```
So for our Tic Tac Toe game, many of our functions will have a signature like State GameState a.

# OUR STATEFUL FUNCTIONS
Now we can examine some of the different functions mentioned above and determine their types. We have for instance, picking a random move:
```haskell
chooseRandomMove :: State GameState TileIndex
chooseRandomMove = do
  game <- get
  let openSpots = [ fst pair | pair <- A.assocs (board game), snd pair == Empty]
  let gen = generator game
  let (i, gen') = randomR (0, length openSpots - 1) gen
  put $ game { generator = gen' }
  return $ openSpots !! i
```
This outputs a TileIndex to us, and modifies the random number generator stored in our state! Now we also have the function applying a move:
```haskell
applyMove :: TileIndex -> State GameState ()
applyMove i = do
  game <- get
  let p = currentPlayer game
  let newBoard = board game A.// [(i, tileForPlayer p)]
  put $ game { currentPlayer = nextPlayer p, board = newBoard }

nextPlayer :: Player -> Player
nextPlayer XPlayer = OPlayer
nextPlayer OPlayer = XPlayer

tileForPlayer :: Player -> TileState
tileForPlayer XPlayer = HasX
tileForPlayer OPlayer = HasO
```
This updates the board with the new tile, and then changes the current player, providing no output.

So finally, we can combine these functions together with do-syntax, and it actually looks quite clean! We don't need to worry about the side effects. The different monadic functions handle them. Here's a sample of what your function might look like to play one turn of the game. At the end, it returns a boolean determining if we've filled all the spaces:
```haskell
resolveTurn :: State GameState Bool
resolveTurn = do
  i <- chooseRandomMove
  applyMove i
  isGameDone

isGameDone :: State GameState Bool
isGameDone = do
  game <- get
  let openSpots = [ fst pair | pair <- A.assocs (board game), snd pair == Empty]
  return $ length openSpots == 0
```
Obviously, there are some more complications for how the game would work in full, but the general idea should be clear. Any additional functions could live within the State monad.

# STATE, IO, AND OTHER LANGUAGES
When thinking about Haskell, it is often seen as a restriction that we can't have global variables like you could with Java class variables. However, we see now this isn't true. We could have a data type with exactly the same functionality as a Java class. We would just have many functions that can modify the global state of the class object using the State monad.

The difference is in Haskell we simply put a label on these types of functions. We don't allow it to happen for free. We want to know when side effects can potentially happen, because knowing when they can happen makes our code easier to reason about. In a Java class, many of the methods won't actually need to modify the state. But they could, which makes it harder to debug them. In Haskell we can simply make these pure functions, and our code will be simpler.

IO is the same way. It's not like we can't perform IO in Haskell. Instead, we want to label the areas where we can, to increase our certainty about the areas where we don't need to. When we know part of our code cannot communicate with the outside world, we can be far more certain of its behavior.

# SUMMARY
That wraps it up for the State monad! Now that we know all these different monad constructs, you might be wondering how we can combine them. What if there was some part of our state that we wanted to be able to modify (using the State monad), but then there was another part that was read-only. How can we get multiple monadic capabilities at the same time? To learn to answer, head to part 6! In the penultimate section of this series, we'll discuss monad transformers. This concept will allow us to compose several monads together into a single monad!

Now that you're starting to understand monads, you can really pick up some steam on learning some useful libraries for important tasks. Download our Production Checklist for some examples of libraries that you can learn!

# Преобразователи Монад

В нескольких прошлых частях серии, мы изучили множество новых монад. В 3 части мы увидели как часто вещи как `Maybe` и `IO` могут быть монадами. Затем в 4 и 5 частях мы изучили Reader, Writer и State монады. С этими монадами на поясе, вы возмоно думаете как можно их объединять. Ответ, как мы обнаружи в этой части, это преобразователи монад.

С пониманием монад, вы открываете больше Haskell возможностей. Но вам всё ещё нужны идеи библиотек Haskell, который позволят вам их испытать. 


# Пример Мотивации
Ранее, мы уже видели как монада `maybe` помогает избежать треугольника судьбы шаблонов кода. Без них, нам нужно проверять каждую функцию на успех. Однако, примеры на которые мы смотрим, где всё является чистым кодом предполагает следующее:
```haskell
main1 :: IO ()
main1 = do
  maybeUserName <- readUserName
  case maybeUserName of
    Nothing -> print "Invalid user name!"
    Just (uName) -> do
      maybeEmail <- readEmail
      case maybeEmail of
        Nothing -> print "Invalid email!"
        Just (email) -> do
          maybePassword <- readPassword
          Case maybePassword of
            Nothing -> print "Invalid Password"
            Just password -> login uName email password

readUserName :: IO (Maybe String)
readUserName = do
  putStrLn "Please enter your username!"
  str <- getLine
  if length str > 5
    then return $ Just str
    else return Nothing

readEmail :: IO (Maybe String)
readEmail = do
  putStrLn "Please enter your email!"
  str <- getLine
  if '@' `elem` str && '.' `elem` str
    then return $ Just str
    else return Nothing

readPassword :: IO (Maybe String)
readPassword = do
  putStrLn "Please enter your Password!"
  str <- getLine
  if length str < 8 || null (filter isUpper str) || null (filter isLower str)
    then return Nothing
    else return $ Just str

login :: String -> String -> String -> IO ()
...
```
В этом примере, все наши потенциальные проблемы кода идут из `IO` монады. Как мы може использовать `Maybe` монаду когда мы уже внутри другой монады?

# Преобразователи Монад
К счастью, мы можем получить желаемое поведение используя преобразователи монад для объединения. В этом примере, мы обернем `IO` действиее внутрь преобразованной монады `MaybeT`.

Преобразователи Монад это оберточный тип. В общем параметризируемый другим монадическим типом. Затем вы можете запустить действие из внутренней монады, в то время пока добавляете ваше собственное поведение для действия объединения в новую монаду. Общий преобразователь добавляет `T` в конец существующей монады. Ниже представленно определение `MaybeT`:
```haskell
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

instance (Monad m) => Monad (MaybeT m) where
  return = lift . return
  x >>= f = MaybeT $ do
    v <- runMaybeT x
    case v of
      Nothing -> return Nothing
      Just y  -> runMaybeT (f y)
```
`MaybeT` сам по себе это newtype. Он содержит обертку над значением `Maybe`. Если тип `m` это `monad`, мы можем так же сделать монаду из `MaybeT`.

Представим наш пример. Мы хотим использовать `MaybeT` для оборачивания  `IO` монады, чтобы запустить `IO` действия. Это значит, что наша новая монада `MaybeT IO`. Наши три вспомогательные функции все возвращают строки, поэтому каждая из них получает тип `MaybeT IO String`. Для преобразования старого `IO` кода в `MaybeT` монаду, всё, что нужно - обернуть `IO` действие в `MaybeT` конструктор.
```haskell
readUserName' :: MaybeT IO String
readUserName' = MaybeT $ do
  putStrLn "Please enter your Username!"
  str <- getLine
  if length str > 5
    then return $ Just str
    else return Nothing

readEmail' :: MaybeT IO String
readEmail' = MaybeT $ do
  putStrLn "Please enter your Email!"
  str <- getLine
  if length str > 5
    then return $ Just str
    else return Nothing

readPassword' :: MaybeT IO String
readPassword' = MaybeT $ do
  putStrLn "Please enter your Password!"
  str <- getLine
  if length str < 8 || null (filter isUpper str) || null (filter isLower str)
    then return Nothing
    else return $ Just str
```
Теперь ы можем обернуть все три этих вызова в одно монадическое действие, и сделать простое сравнение для получения результата. Мы воспользуемся `runMaybeT` функцией для развертывания значения `Maybe` из `MaybeT`:
```haskell
main2 :: IO ()
main2 = do
  maybeCreds <- runMaybeT $ do
    usr <- readUserName
    email <- readEmail
    pass <- readPassword
    return (usr, email, pass)
  case maybeCreds of
    Nothing -> print "Couldn't login!"
    Just (u, e, p) -> login u e p
```
И этот новый код бдует иметь правильное простое поведение для `Maybe` монады. Если какая-то функция `read` упадет, наш код сразу же вернет `Nothing`.

# Добавление уровней. 
Вот и мы дождались долгожданное части о преобразователях монад. Так как наш новосозданный тип сам по себе монада, мы межем обернуть её внутри другого преборазователя. Почти все распространненые монады имеют преобразователь типа, `MaybeT` в том числе, это преобразователь для обычной `Maybe` монады. 

Для быстрого примера, предположим, у нас есть `Env` тип содержащий пользовательскую информацию.  Мы можем обернуть это окружение в `Reader`. Однако, мы хоти всё еще иметь доступ к `IO` функциональности, поэтму мы воспользумся `Reader` преобразователем. Затем обернем резултат с помощью  `MaybeT`.
```haskell
type Env = (Maybe String, Maybe String, Maybe String)

readUserName'' :: MaybeT (ReaderT Env IO) String
readUserName'' = MaybeT $ do
  (maybeOldUser, _, _) <- ask
  case maybeOldUser of
    Just str -> return $ Just str
    Nothing -> do
      -- lift allows normal IO functions from inside ReaderT Env IO!
      lift $ putStrLn "Please enter your Username!"
      input <- lift getLine
      if length input > 5
        then return (Just input)
        else return Nothing
```
Заметим, что у нам нужно использовать `lift` для запуска `IO` функции `getLine`. В преобразователе монады, `lift` функция позволяет нам запустить действия нижележащей монады. Это поведение захватывается классом `MonadTrans`:
```haskell
class MonadTrans t where
  lift :: (Monad m) => m a -> t m a
```
Использование `lift` в `ReaderT Env IO` действии позвляет `IO` функцияю Использование типа шаблона из класса, мы можем заменить `Reader Env` на `t` и `IO` на `m`.

Внутри `MaybeT (ReaderT Env IO)` функции, вызываемой `lift` позволяет вам запустить функцию `Reader`. Нам не нужно то что выше, так как набор кода лежит в `Reader` действии в обертке `MaybeT` конструктора.

Чтобы понять идею лифтинга, подумайте о уровне вашей монады как о стеке. Когда вы имеете `ReaderT Env IO` действие, представьте, что `Reader Env` монада сверху `IO` монады. `IO` действие лежит на нижнем уровне. Поэтому, чтобы запустить всё это дело с верхнего слоя, вам нужно сначала подняться. Если ваш стек имеет больше чем 2 слоя, вы можете подниматься несколько раз. Вызывая дважды  `MaybeT (ReaderT Env IO)` монаду позволит вам вызывать `IO` функцию.

Не удобно каждый раз знать сколько раз тебе нужно вызывать функцию `lift` для получения текущего уровня. Отсюда вспомогательная функйия часто используется для этого. Вдобавок, после преобразования монады, можно запустить несколько уровней, типы могут становится сложнее. Поэтому обычно используют библиотеку `synonyms`.
```haskell
type TripleMonad a = MaybeT (ReaderT Env IO) a

performReader :: ReaderT Env IO a -> TripleMonad a
performReader = lift

performIO :: IO a -> TripleMonad a
performIO = lift . lift
```
# Типоклассы
В качестве похожей идеи, есть `typeclass` который позволяет нам сделать определенные предположения о стеке монады. Для примера, вас часто не волнует, что именно в стеке, но вам нужен `IO` где-то внутри. В этом и заключается цель использования `MondaIO` типокласса. 
```haskell
class (Monad m) => MonadIO m where
  liftIO :: IO a -> m a
```
We can use this behavior to get a function to print even when we don't know its exact monad:
```haskell
debugFunc :: (MonadIO m) => String -> m ()
debugFunc input = liftIO $ putStrLn ("Successfully produced input: " ++ input)
```
Даже не смотря на то, что функция явно не находится в `MaybeT IO`, мы можем написать нашу версию `main` функции чтобы использовать её.
```haskell
main3 :: IO ()
main3 = do
  maybeCreds <- runMaybeT $ do
    usr <- readUserName'
    debugFunc usr
    email <- readEmail'
    debugFunc email
    pass <- readPassword'
    debugFunc pass
    return (usr, email, pass)
  case maybeCreds of
    Nothing -> print "Couldn't login!"
    Just (u, e, p) -> login u e p
```
> Вы не можете, в общем, обернуть другую монаду с помощью `IO` монады используя преобразователь. Однако, можно сделать другое монадическое значение чтобы вренуть тип `IO` действия.
```haskell
func :: IO (Maybe String)
-- This type makes sense

func2 :: IO_T (ReaderT Env (Maybe)) string
-- This does not exist
```
# Выводы
Теперь, вы знаете, как объединять ваши монады, вы почти завершили понинмание ключевых идей! Вы, возможно, хотите попробовать начать писать достаточно сложный код. Но, чтобы научиться владеть монадами, вам нужно знать как делать свою собственную монаду, и для этого вам нужно понять последню идею. Это идея типа `laws`. Каждая структура, которую мы прошли в этой части лекций, связана с `laws`. И чтобы ваши примеры имели смысл, они должны следовать `laws`(т.е. закону). Проверьте 7 главу, чтобы понять, понимаете ли вы что происходит.

# Законы Монад

Добро пожаловать в заключительную часть серии о монадах в Haskell. Сейчас мы уже знаем большишнство идей лежащих в основе зная их тонкости для использования в программах. Но есть еще абстрактные идеи, которые нам нужно изучить, которые связанны со всеми этими структурами. Это записи структурных "законов". Эти правила для typeclass должны выполняться чтобы пересекаться с ожиданиями других программистов. 



# Жизнь без законов
Помните, что Haskell отражает каждый абстрактный класс с помощью type class. Каждый из этих type class имеет одину или две главные функции. Поэтому, каждый раз реализуя эти функции и её проверки типов, мы получаем функтор/аппликатив/монаду, правильно?

Не совсем. Да, ваша программа будет собираться и у вас будет возможность использовать её объекты. Но это не значит, что ваш объект следует математическим конструктам. Если нет, ваш объект не будет полноценным для других программистов. Каждый type class имеет свои законы. Для примера, давайте вернемся к `GovDirectory` типу, который мы создавали в статье про функторы. Предположим мы сделали различные объекты функторов:
```haskell
data GovDirectory a = GovDirectory {
  mayor :: a,
  interimMayor :: Maybe a,
  cabinet :: Map String a,
  councilMembers :: [a]
}

instance Functor GovDirectory where
  fmap f oldDirectory = GovDirectory {
    mayor = f (mayor oldDirectory),
    interimMayor = Nothing,
    cabinet = f <$> cabinet oldDirectory,
    councilMembers = f <$> councilMembers oldDirectory
  }
```
Насколько видно, это нарушает один из законов функтора. В этом случае, это будет не настоящий функтор. Его поведение должно смущать любого программиста пытающегося его использовать. Мы должны позаботиться о том, чтобы убедиться что наш экземпляр имеет смысл. Как только, вы  это почувствуете для `type class`, значит вы сделали экземпляр по правилу. Не переживайте если вас что-то смущает. Эта статья очень математичка, и вы не сразу поймете, все идеи, что тут предложены. Вы можете понять и использовать эти классы без знания этих законов. Ну что же, окунемся без суеты в эти законы. 

# Законы функторов
Есть два закона функтороов. Первый - закон идентичности. Мы посмотрим на некотороый вариант этой идеи для каждого из этих `type class`. Вспомните, как `fmap` функция работаетс содержанием. Если мы применим нашу функцию идентичности к контейнеру, результатом будет тот же объект. 
```haskell
fmap id = id
```
Другими словами, наш функтор не должен применять какие-то дополнительные преобразования или сторонние эффекты. Он должен только применять функцию. Второй закон это композиционный. Он гласит, что реализация нашго функтора не должна ломать идею нашей функции.
```haskell
fmap (g . f) = fmap g . fmap f

-- For reference, remember the type of the composition operator:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
```
С другой стороы, мы можем собрать две функции, и объединить результат в функции поверх контейнера. С другой стороны, мы применяем первую функцию, получаем результат, и применяем вторую функции поверх. Второй закон говорит, что результаты должны быть одинаковыми. Звучит это сложно. Но вам не нужно переживать. Скорей всего елсли вы сломаете закон композиции в Haskell, скорей всего вы сломаете и закон идентичности. 

У нас всего два закона, поэтому двинем дальше.

# Аппликативные законы 
Аппликативные функторы - это немного сложнее чем кажется. Они имеют 4 различных закона. Первый достаточно просто. Это еще один закон идентичности: 
```haskell
pure id <*> v = v
```
Слева - обертка для идентичной функции. Затем мы применяем её к контейнеру. Закон аппликативной идентичности говорит, что в результате должен быть тот же объект. Достаточно просто.

Второй закон это закон гомоморфизма. Представим, мы оборачиваем функцию и другие объекты в чистые. Мы можем затем применить обернутую функцию поверх нормального объекта, и затем оберунть их в чистые. Закон гомоморфизма говорит, что эти результаты должны быть одинаковы. 
```haskell
pure f <*> pure x = pure (f x)
```
Мы должны увидеть чистый шаблон. Поверх этого можно сказать, что большая часть этих законов гласит, что `type class` это контенеры. Фнукция `type class` не должна иметь сторонних эффектов. Все они, что они должны - облегчать обертывание, развертывание и проеобразование данных.

Третий закон - закон обмена. Он по-сложнее. Закон говорит, что от порядка оборачивания ничего не должно зависеть. С одной стороны, мы применяем любой аппликтор над обернутым в чистую функцию объектом. С другой - первое мы применяем функцию к объекту как к аргументу. Затем применяем её к первому аппликативу. Должно получиться одно и то же. 
```haskell
u <*> pure y = pure ($ y) <*> u
```
Последний закон аппликативности, копирует второй закон функтора.  Это закон композиции. Он гласит, что композиция функторов не должна влиять на результат. 
```haskell
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
```
Явное число законов, может быть переполняющим. Однако, экземпляр который вы создадиде скорей всего будет следовать законам. Двигаемся дальше!

# Законы монад
У монад есть три закона. Первые два это просто законы идентичности. Как и в прошлые разы.
```haskell
return a >>= f = f
m >>= return = m
```
Есть левая и правая части. Они утверждают, что единственное что можно делать функции это оборачивать объект(знакомо?). Нельзя изменять данные как угодно. Главный вывод такой: что ниже приведнный пример кодов одинаков. 
```haskell
func1 :: IO String
func1 = do
  str <- getLine
  return str

func2 :: IO String
func2 = getLine
```
Третий закон звучит интереснее. Он говорит нам, что асоциативность хранится внутри монад. 
```haskell
(m >>= f) >>= g = m >>= (\x -> f x >>= g)
```
Но мы видим этот третий закон имеет паралельные структуры с другими композиционными законами. В первом случае, мы применяем две функции в два захода. Во втором случае, мы собирае сначала функцию, и только уже потом применяем результать. Они должны быть одинаковы.

В результате, есть две идеи из всех законов. Первый, идентичность должна сохраняться и в обернутых функциях, как чистых так и в возвращяемых. Второе, функция композиции должна храниться во всех структурах.

# Проверка законов. 

Как я говорил, большая часть экземпляров, которые вы прошли, будут естественно следовать правилам. С опытом использования различных типо классов, это будет становится правдой. Haskell отличный инструмент проверки ваших экземпляров проходищих определенный закон. 

Эта утилита `QuickCheck`. Она может принимать любое правило, создавать множество разных случаев тестирования в нашем экземпляре функтора `GovDirectory`. Посмотрим, как `QuickCheck` доказывает свое начальное падение, и полный успех. Для начала нужно реализовать типо класс над нашим типом. Мы можем сделать это вместе с внутренним типом `Arbtrary`, такой как встроенный тип `string`. Затем мы будем использовать все другие экземпляры `Arbitrary`, которые существуют вокруг нашего типо класса.
```haskell
instance Arbitrary a => Arbitrary (GovDirectory a) where
  arbitrary = do
    m <- arbitrary
    im <- arbitrary
    cab <- arbitrary
    cm <- arbitrary
    return $ GovDirectory
      { mayor = m
      , interimMayor = im
      , cabinet = cab
      , councilMembers = cm
      }
```
Как только вы это выполните, вы можете описать тестовый случай для частного правила. Тогда, мы проверяем идентичность функции для функтора. 
```haskell
main :: IO ()
main = quickCheck govDirectoryFunctorCheck

govDirectoryFunctorCheck :: GovDirectory String -> Bool
govDirectoryFunctorCheck gd = fmap id gd == gd
```
Теперь, давайте проверим на сломанном экземплеря, приведенном выше. Мы можем увидеть, что простой тест упадет. 
```haskell
*** Failed! Falsifiable (after 2 tests):
GovDirectory {mayor = "", interimMayor = Just "\156", cabinet = fromList [("","")], councilMembers = []}
```
Сообщение уточняет нам что тест `arbitrary` экземпляра не пройден. Теперь предположим правильнй экземпляр:
```haskell
interimMayor = f <$> (interimMayor oldDirectory),
```
Тест пройден!

```haskell
+++ OK, passed 100 tests.
```
# Выводы
Так мы можем обертывать наши монады! Помните, что если любая из этих идей до сих пор вас сммущает, не переживайте, и перечитывайте информаци которую вы уже читали. Мы начали с изучения основ: функторы, аппликативные функторы и монады. Пошли дальше и увидели монады еще полезнее `Reader`, `Writer` и `State`. Теперь мы изучили как это всё объединять вместе используя преобразователи монад.