# Теоретические задачи для курса по Haskell
# Правила выполнения
Данное задание, предполагает что Вы создадите пакет `hw0` в Вашей папке домашнего задания.
Решения должны быть оформлены, как код на Haskell (иногда с комментариями где требуется).
Обратите внимание, что некоторые конструкции не объяснялись на первой лекции,
но предполагается, что все они будет объяснены за будущие лекции,
которые будут рассказаны до дедлайна по этому заданию.
### Задание 1.
Заселить следующие типы
(формально `undefined` тоже считается заселением типа (причем любого),
но в решении ожидается что-то отличное от `undefined`):
```haskell
distributivity
:: Either a (b, c)
-> (Either a b, Either a c)
distributivity = undefined
```
```haskell
associator
:: (a, (b, c))
-> ((a, b), c)
associator = undefined
```
```haskell
{-# LANGUAGE TypeOperators #-}
type (<->) a b = (a -> b, b -> a)
eitherAssoc
:: Either a (Either b c)
<-> Either (Either a b) c
eitherAssoc = undefined
```
### Задание 2
Заселить среди данных типов те, которые возможно.
```haskell
import Data.Void (Void)
type Neg a = a -> Void
doubleNeg :: a -> Neg (Neg a)
doubleNeg = undefined
excludedNeg :: Neg (Neg (Either a (Neg a)))
excludedNeg = undefined
pierce :: ((a -> b) -> a) -> a
pierce = undefined
doubleNegElim :: Neg (Neg a) -> a
doubleNegElim = undefined
thirdNegElim :: Neg (Neg (Neg a)) -> Neg a
thirdNegElim = undefined
```
### Задание 3
Предположим у нас есть функция:
```haskell
s :: (a -> b -> c) -> (a -> b) -> a -> c
s f g x = f x (g x)
```
Реализовать с помощью `s` и `const` следующие функции:
```haskell
composition :: (b -> c) -> (a -> b) -> a -> c
composition = undefined
```
(должна вести себя аналогично оператору `(.)` из стандартной библиотеки)
```haskell
identity :: a -> a
identity = undefined
```
(должна вести себя аналогично тождественной функции `id`, определенной в Prelude)
```haskell
contraction :: (a -> a -> b) -> a -> b
contraction = undefined
```
```haskell
permutation :: (a -> b -> c) -> b -> a -> c
permutation = undefined
```
### Задание 4
В модуле `Data.Function` определена функция `fix`, которая является аналогом комбинатора неподвижной точки:
```haskell
fix :: (a -> a) -> a
```
Реализовать с помощью `fix` следующие функции:
```haskell
iterateElement :: a -> [a]
iterateElement = undefined
```
Данная функция должна удовлетворять равенству:
`iterateElement x == [x, x..]`
```haskell
fibonacci :: Integer -> Integer
fibonacci = undefined
```
```haskell
factorial :: Integer -> Integer
factorial = undefined
```
```haskell
mapFix :: (a -> b) -> [a] -> [b]
mapFix = undefined
```
### Задание 5
Как вы знаете из курса по теории типов, в лямбда-исчисления можно кодировать натуральные числа и арифметические операции над ними.
Определим тип нумералов Черча следующим образом:
```haskell
type Nat a = (a -> a) -> a -> a
```
Определим нуль:
```haskell
zero :: Nat a
zero f x = x
```
Определить функцию-последователя (он же инкремент):
```haskell
succChurch :: Nat a -> Nat a
succChurch = undefined
```
Реализовать арифметические операции (сложение и умножение):
```haskell
churchPlus, churchMult
:: Nat a -> Nat a -> Nat a
churchPlus = undefined
churchMult = undefined
```
Реализовать функцию, которая по нумералу Черча сопоставляет обычное целое число:
```haskell
churchToInt :: Nat Integer -> Integer
churchToInt = undefined
```
Данная функция должна удовлетворять следующим равенствам:
1. `churchToInt zero = 0`
2. `churchToInt (succChurch number) = 1 + churchToInt number`
3. `churchToInt (churchPlus m n) = churchToInt m + churchToInt n`
4. `churchToInt (churchMult m n) = churchToInt m * churchToInt n`
### Задание 6
Определить слабую головную нормальную форму:
```haskell
distributivity (Left ("harold" ++ " hide " ++ "the " ++ "pain"))
```
```haskell
import Data.Maybe (mapMaybe)
null $ mapMaybe foo "pole chudes ochen' chudesno"
```
где
```haskell
foo :: Char -> Maybe Double
foo char =
case char == 'o' of
True -> Just $ exp pi
False -> Nothing
```
### Задание 7
Определить типы подтермов в следующих выражениях
(включая тип исходного выражения):
```haskell
null . head $ map (uncurry id) [((++) "Dorian ", " Grey")]
```
```haskell
(\x -> zip (lefts x) (rights x)) [Left (1 + 2), Right (2 ^ 6)]
```
```haskell
let impl = \x y -> not x || y in
let isMod2 = \x -> x `mod` 2 == 0 in
let isMod4 = \x -> x `mod` 4 == 0 in
\x -> (isMod4 x) `impl` (isMod2 x)
```
Разрешается выносить подвыражения в блок `let` или `where`, чтобы улучшить читабельность кода.
Разрешается указать частный тип, который получится из общего после [мономорфизации](https://wiki.haskell.org/Monomorphism_restriction).