├── .gitignore ├── README.md ├── lection1 ├── step1.1.6.md ├── step1.2.10.md ├── step1.2.7.md ├── step1.3.10.md ├── step1.3.12.md ├── step1.3.4.md ├── step1.3.5.md ├── step1.3.7.md ├── step1.3.8.md ├── step1.4.11.md ├── step1.4.6.md ├── step1.4.8.md ├── step1.4.9.md ├── step1.5.10.md ├── step1.5.4.md ├── step1.5.7.md ├── step1.5.8.md ├── step1.6.4.md ├── step1.6.6.md ├── step1.6.8.md └── step1.6.9.md └── lection2 ├── step2.1.3.md ├── step2.1.4.md ├── step2.1.7.md ├── step2.1.9.md ├── step2.2.3.md ├── step2.2.5.md ├── step2.2.7.md ├── step2.2.8.md ├── step2.2.9.md ├── step2.3.3.md ├── step2.3.5.md ├── step2.3.7.md ├── step2.3.9.md ├── step2.4.3.md ├── step2.4.5.md ├── step2.4.7.md ├── step2.4.9.md ├── step2.5.11.md ├── step2.5.13.md ├── step2.5.3.md ├── step2.5.5.md ├── step2.5.7.md ├── step2.5.9.md ├── step2.6.3.md └── step2.6.5.md /.gitignore: -------------------------------------------------------------------------------- 1 | # haskell ignore patterns 2 | 3 | dist 4 | dist-* 5 | cabal-dev 6 | *.o 7 | *.hi 8 | *.chi 9 | *.chs.h 10 | *.dyn_o 11 | *.dyn_hi 12 | .hpc 13 | .hsenv 14 | .cabal-sandbox/ 15 | cabal.sandbox.config 16 | *.prof 17 | *.aux 18 | *.hp 19 | .stack-work/ 20 | 21 | # idea ignore patterns 22 | 23 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 24 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 25 | 26 | .idea 27 | 28 | # User-specific stuff: 29 | .idea/workspace.xml 30 | .idea/tasks.xml 31 | .idea/dictionaries 32 | .idea/vcs.xml 33 | .idea/jsLibraryMappings.xml 34 | 35 | # Sensitive or high-churn files: 36 | .idea/dataSources.ids 37 | .idea/dataSources.xml 38 | .idea/dataSources.local.xml 39 | .idea/sqlDataSources.xml 40 | .idea/dynamic.xml 41 | .idea/uiDesigner.xml 42 | 43 | # Gradle: 44 | .idea/gradle.xml 45 | .idea/libraries 46 | 47 | # Mongo Explorer plugin: 48 | .idea/mongoSettings.xml 49 | 50 | ## File-based project format: 51 | *.iws 52 | *.ips 53 | 54 | ## Plugin-specific files: 55 | 56 | # IntelliJ 57 | /out/ 58 | 59 | # mpeltonen/sbt-idea plugin 60 | .idea_modules/ 61 | 62 | # JIRA plugin 63 | atlassian-ide-plugin.xml 64 | 65 | # Crashlytics plugin (for Android Studio and IntelliJ) 66 | com_crashlytics_export_strings.xml 67 | crashlytics.properties 68 | crashlytics-build.properties 69 | fabric.properties 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # functional_programming_in_haskell -------------------------------------------------------------------------------- /lection1/step1.1.6.md: -------------------------------------------------------------------------------- 1 | Запустите ваш текстовой редактор и создайте файл Hello.hs, содержащий следующую строку кода: 2 | ```haskell 3 | main = putStrLn "Hello, world!" 4 | ``` 5 | Вызовите теперь с помощью средств вашей ОС интерпретатор GHCi c параметром — именем файла исходного кода: 6 | ``` 7 | ghci Hello.hs 8 | ``` 9 | (Файл должен располагаться в том же каталоге, откуда происходит вызов интерпретатора.) Проверьте, что загрузка модуля прошла успешно, вызвав в интерпретаторе определенную вами функцию main: 10 | ``` 11 | GHCi> main 12 | Hello, world! 13 | ``` 14 | Какое приглашение на самом деле выдает командная строка интерпретатора (в предыдущем примере интерпретатор выдал приглашение GHCi>)? 15 | 16 | Answer: 17 | ```haskell 18 | *Main> 19 | ``` 20 | -------------------------------------------------------------------------------- /lection1/step1.2.10.md: -------------------------------------------------------------------------------- 1 | Напишите реализацию функции sign, которая возвращает 1, если ей передано положительное число, (-1), если отрицательное, и 0 в случае, когда передан 0. 2 | 3 | ``` 4 | GHCi> sign (-100) 5 | -1 6 | ``` 7 | Answer: 8 | 9 | ```haskell 10 | sign x = if x > 0 then 1 else if x < 0 then (-1) else 0 11 | ``` -------------------------------------------------------------------------------- /lection1/step1.2.7.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию трех аргументов lenVec3, которая вычисляет длину трехмерного вектора. Аргументы функции задают декартовы координаты конца вектора, его начало подразумевается находящимся в начале координат. Для извлечения квадратного корня воспользуйтесь функцией sqrt, определенной в стандартной библиотеке. 2 | 3 | ``` 4 | GHCi> lenVec3 2 3 6 5 | 7.0 6 | ``` 7 | Answer: 8 | 9 | ```haskell 10 | lenVec3 x y z = sqrt (x^2 + y^2 + z^2) 11 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.10.md: -------------------------------------------------------------------------------- 1 | Попробуйте вычислить значение выражения 2 | 3 | ``` 4 | (`mod` 14) ((+ 5) 10), 5 | ``` 6 | не используя GHCi. (Функция mod возвращает остаток от целочисленного деления первого своего аргумента на второй.) 7 | 8 | Answer: 9 | 10 | ``` 11 | 1 12 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.12.md: -------------------------------------------------------------------------------- 1 | Используя оператор $, перепишите выражение 2 | 3 | ```haskell 4 | logBase 4 (min 20 (9 + 7)) 5 | ``` 6 | без скобок. (Разделяйте все токены одним пробелом.) 7 | 8 | Answer: 9 | 10 | ```haskell 11 | logBase 4 $ min 20 $ 9 + 7 12 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.4.md: -------------------------------------------------------------------------------- 1 | Попробуйте вычислить значение выражения 2 ^ 3 ^ 2, не используя GHCi. 2 | 3 | Answer: 4 | 5 | ``` 6 | 512 7 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.5.md: -------------------------------------------------------------------------------- 1 | Попробуйте вычислить значение выражения 2 | 3 | ```haskell 4 | (*) 2 ((+) 1 4) ^ 2, 5 | ``` 6 | не используя GHCi. 7 | 8 | Answer: 9 | 10 | ``` 11 | 100 12 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.7.md: -------------------------------------------------------------------------------- 1 | ```haskell 2 | infixl 6 *+* 3 | (*+*) a b = a ^ 2 + b ^ 2 4 | ``` 5 | попробуйте устно вычислить значение выражения 6 | 7 | ```haskell 8 | 1 + 3 *+* 2 * 2. 9 | ``` 10 | 11 | Answer: 12 | 13 | ``` 14 | 32 15 | ``` -------------------------------------------------------------------------------- /lection1/step1.3.8.md: -------------------------------------------------------------------------------- 1 | Реализуйте оператор |-|, который возвращает модуль разности переданных ему аргументов: 2 | 3 | ``` 4 | GHCi> 5 |-| 7 5 | 2 6 | ``` 7 | Answer: 8 | 9 | ```haskell 10 | x |-| y = abs(x-y) 11 | ``` -------------------------------------------------------------------------------- /lection1/step1.4.11.md: -------------------------------------------------------------------------------- 1 | Будем задавать точки на плоскости парами типа 2 | ``` 3 | (Double, Double). 4 | ``` 5 | Реализуйте функцию dist, которая возвращает расстояние между двумя точками, передаваемыми ей в качестве аргументов. 6 | 7 | ```haskell 8 | dist :: (Double, Double) -> (Double, Double) -> Double 9 | dist p1 p2 = ??? 10 | ``` 11 | 12 | Answer: 13 | 14 | ```haskell 15 | dist :: (Double, Double) -> (Double, Double) -> Double 16 | dist x y = sqrt ((fst x - fst y)^2 + (snd x - snd y)^2) 17 | ``` -------------------------------------------------------------------------------- /lection1/step1.4.6.md: -------------------------------------------------------------------------------- 1 | Вспомним функцию discount, которая возвращала итоговую сумму покупки с возможной скидкой. 2 | В качестве параметров ей передавались сумма без скидки sum, процент скидки proc, причем скидка начислялась, 3 | если переданная сумма превышает порог limit. Все эти параметры, как и возвращаемое значение, можно хранить в типе Double. 4 | (Здесь следует отметить, что в реальных финансовых приложениях использовать тип с плавающей точкой для хранения подобной информации не рекомендуется.) 5 | Тип функции можно задать в файле исходного кода вместе с ее определением: 6 | 7 | ```haskell 8 | discount :: Double -> Double -> Double -> Double 9 | discount limit proc sum = if sum >= limit then sum * (100 - proc) / 100 else sum 10 | ``` 11 | 12 | Отметим, что объявление типа необязательно, хотя часто рекомендуется в качестве документации. Его обычно располагают перед определением функции, хотя это объявление верхнего уровня можно расположить в любом месте файла с исходным кодом. 13 | 14 | Запишите тип функции standardDiscount, определенной как частичное применение функции discount: 15 | 16 | ```haskell 17 | standardDiscount :: ??? 18 | standardDiscount = discount 1000 5 19 | ``` 20 | 21 | Answer: 22 | 23 | ```haskell 24 | discount :: Double -> Double -> Double -> Double 25 | discount limit proc sum = if sum >= limit then sum * (100 - proc) / 100 else sum 26 | 27 | standardDiscount :: Double -> Double 28 | standardDiscount = discount 1000 5 29 | ``` 30 | -------------------------------------------------------------------------------- /lection1/step1.4.8.md: -------------------------------------------------------------------------------- 1 | Воспользовавшись справочной системой Hoogle, найдите имя функции типа Char -> Char, переводящей символ в нижний регистр. 2 | 3 | Answer: 4 | 5 | ```haskell 6 | toLower 7 | ``` -------------------------------------------------------------------------------- /lection1/step1.4.9.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию twoDigits2Int, которая принимает два символа и возвращает число, 2 | составленное из этих символов, если оба символа числовые, и 100 в противном случае. 3 | (Первый символ рассматривается как количество десятков, второй — единиц.) 4 | 5 | ``` 6 | GHCi> twoDigits2Int '4' '2' 7 | 42 8 | ``` 9 | 10 | Answer: 11 | 12 | ```haskell 13 | import Data.Char 14 | twoDigits2Int :: Char -> Char -> Int 15 | twoDigits2Int x y = if isDigit x && isDigit y then 10 * digitToInt x + digitToInt y else 100 16 | ``` -------------------------------------------------------------------------------- /lection1/step1.5.10.md: -------------------------------------------------------------------------------- 1 | Реализация функции для вычисления числа Фибоначчи, основанная на прямом рекурсивном определении, крайне неэффективна - количество 2 | вызовов функции растет экспоненциально с ростом значения аргумента. GHCi позволяет отслеживать использование 3 | памяти и затраты времени на вычисление выражения, для этого следует выполнить команду :set +s: 4 | 5 | ``` 6 | GHCi> :set +s 7 | GHCi> fibonacci 30 8 | 832040 9 | (8.36 secs, 298293400 bytes) 10 | ``` 11 | 12 | С помощью механизма аккумуляторов попробуйте написать более эффективную реализацию, имеющую линейную сложность 13 | (по числу рекурсивных вызовов). Как и в предыдущем задании, функция должна быть определена для всех целых чисел. 14 | 15 | Answer: 16 | 17 | ```haskell 18 | fibonacci :: Integer -> Integer 19 | fibonacci n = f1 n 0 0 1 where f1 n k a b | n == k = a 20 | | n > 0 = f1 n (k + 1) (a + b) a 21 | | n < 0 = (-1)^(-n+1) * f1 (-n) (k+1) (a+b) a 22 | ``` -------------------------------------------------------------------------------- /lection1/step1.5.4.md: -------------------------------------------------------------------------------- 1 | Определите функцию, вычисляющую двойной факториал, то есть произведение натуральных чисел, 2 | не превосходящих заданного числа и имеющих ту же четность. 3 | 4 | Например: 5 | ``` 6 | 7!!=7⋅5⋅3⋅1, 7 | 8!!=8⋅6⋅4⋅2. 8 | ``` 9 | Предполагается, что аргумент функции может принимать только неотрицательные значения. 10 | 11 | Answer: 12 | 13 | ```haskell 14 | doubleFact :: Integer -> Integer 15 | doubleFact n = if n <= 1 then 1 else n * doubleFact(n-2) 16 | ``` -------------------------------------------------------------------------------- /lection1/step1.5.7.md: -------------------------------------------------------------------------------- 1 | В последнем примере предыдущего шага в охранном выражении использовался идентификатор otherwise. 2 | Это не ключевое слово, а константа, определенная для удобства в стандартной библиотеке: 3 | 4 | ``` 5 | otherwise = ? 6 | ``` 7 | 8 | Как вы думаете, какова правая часть её определения? 9 | 10 | Answer: 11 | 12 | ``` 13 | True 14 | ``` -------------------------------------------------------------------------------- /lection1/step1.5.8.md: -------------------------------------------------------------------------------- 1 | Последовательность чисел Фибоначчи 2 | ``` 3 | 0,1,1,2,3,5,8,13,21,… 4 | ``` 5 | легко определить рекурсивно, задав два первых терминирующих значения и определив любое последующее как сумму двух непосредственно предыдущих: 6 | 7 | ``` 8 | F0=0 9 | 10 | F1=1 11 | 12 | Fn=Fn−1+Fn−2 13 | ``` 14 | 15 | На Haskell данное определение задаётся следующей функцией: 16 | 17 | ```haskell 18 | fibonacci 0 = 0 19 | fibonacci 1 = 1 20 | fibonacci n = fibonacci (n - 1) + fibonacci (n - 2) 21 | ``` 22 | 23 | Эта функция определена лишь для неотрицательных чисел. Однако, из данного выше определения можно вывести 24 | формулу для вычисления чисел Фибоначчи при отрицательных индексах, при этом последовательность будет следующей: 25 | 26 | ``` 27 | F−1=1,F−2=−1,…,F−10=−55,… 28 | ``` 29 | 30 | Измените определение функции fibonacci так, чтобы она была определена для всех целых чисел и порождала при отрицательных аргументах указанную последовательность. 31 | 32 | Answer: 33 | 34 | ```haskell 35 | fibonacci :: Integer -> Integer 36 | fibonacci n | n == 0 = 0 37 | | n == 1 = 1 38 | | n == (-1) = 1 39 | | n > 1 = fibonacci(n-1) + fibonacci(n-2) 40 | | n < (-1) = (-1) ^ ((-n) + 1) * fibonacci(-n) 41 | ``` 42 | -------------------------------------------------------------------------------- /lection1/step1.6.4.md: -------------------------------------------------------------------------------- 1 | Не используя GHCi, определите строку, которая является значением выражения 2 | 3 | ```haskell 4 | (let x = 'w' in [x,'o',x]) ++ "!". 5 | ``` 6 | 7 | Answer: 8 | 9 | ``` 10 | wow! 11 | ``` -------------------------------------------------------------------------------- /lection1/step1.6.6.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию seqA, находящую элементы следующей рекуррентной последовательности 2 | 3 | ``` 4 | a0=1;a1=2;a2=3;ak+3=ak+2+ak+1−2ak. 5 | ``` 6 | Попытайтесь найти эффективное решение. 7 | 8 | ``` 9 | GHCi> seqA 301 10 | 1276538859311178639666612897162414 11 | ``` 12 | 13 | Answer: 14 | 15 | ```haskell 16 | seqA :: Integer -> Integer 17 | seqA n | n == 0 = 1 18 | | n == 1 = 2 19 | | n == 2 = 3 20 | | otherwise = h n 1 2 3 21 | 22 | h :: Integer -> Integer -> Integer -> Integer -> Integer 23 | h n a b c | n <= 2 = c 24 | | otherwise = h (n-1) b c (c + b - 2*a) 25 | ``` -------------------------------------------------------------------------------- /lection1/step1.6.8.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию, находящую сумму и количество цифр заданного целого числа. 2 | 3 | ```haskell 4 | sum'n'count :: Integer -> (Integer, Integer) 5 | sum'n'count x = undefined 6 | ``` 7 | 8 | ``` 9 | GHCi> sum'n'count (-39) 10 | (12,2) 11 | Time Limit: 5 seconds 12 | Memory Limit: 256 MB 13 | ``` 14 | 15 | Answer: 16 | 17 | ```haskell 18 | sum'n'count :: Integer -> (Integer, Integer) 19 | sum'n'count n | n == 0 = (0,1) 20 | | n < 0 = sum'n'count (-n) 21 | | otherwise = h n 0 0 where 22 | h n s k | n == 0 = (s,k) 23 | | otherwise = h (div n 10) (s + mod n 10) (k+1) 24 | ``` 25 | -------------------------------------------------------------------------------- /lection1/step1.6.9.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию, находящую значение определённого интеграла от заданной функции f на 2 | заданном интервале [a,b] методом трапеций. (Используйте равномерную сетку; достаточно 1000 элементарных отрезков.) 3 | 4 | ```haskell 5 | integration :: (Double -> Double) -> Double -> Double -> Double 6 | integration f a b = undefined 7 | ``` 8 | ``` 9 | GHCi> integration sin pi 0 10 | -2.0 11 | ``` 12 | 13 | Результат может отличаться от -2.0, но не более чем на 1e-4. 14 | 15 | Answer: 16 | 17 | ```haskell 18 | integration :: (Double -> Double) -> Double -> Double -> Double 19 | integration f a b | a == b = 0 20 | | a > b = -integration f b a 21 | | otherwise = h * (((f a) + (f b))/2 + sum f a b h) where 22 | h = (b - a) / 1000 23 | sum f a b h = if (a + h) < b - h/2 then f (a + h) + sum f (a + h) b h else 0 24 | ``` 25 | -------------------------------------------------------------------------------- /lection2/step2.1.3.md: -------------------------------------------------------------------------------- 1 | Напишите функцию трех аргументов getSecondFrom, полиморфную по каждому из них, которая полностью игнорирует первый 2 | и третий аргумент, а возвращает второй. Укажите ее тип. 3 | 4 | ``` 5 | GHCi> getSecondFrom True 'x' "Hello" 6 | 'x' 7 | GHCi> getSecondFrom 'x' 42 True 8 | 42 9 | ``` 10 | 11 | Answer: 12 | 13 | ```haskell 14 | getSecondFrom :: t -> t2 -> t1 -> t2 15 | getSecondFrom a b c = b 16 | ``` -------------------------------------------------------------------------------- /lection2/step2.1.4.md: -------------------------------------------------------------------------------- 1 | Сколько разных всегда завершающихся функций с типом 2 | ``` 3 | a -> a -> b -> a -> a 4 | ``` 5 | можно реализовать? 6 | 7 | Две функции одинаковой арности считаются разными, если существует набор значений их аргументов, на котором они дают разные результирующие значения. 8 | 9 | Answer: 10 | 11 | ``` 12 | 3 13 | ``` -------------------------------------------------------------------------------- /lection2/step2.1.7.md: -------------------------------------------------------------------------------- 1 | В модуле Data.Function определена полезная функция высшего порядка 2 | ```haskell 3 | on :: (b -> b -> c) -> (a -> b) -> a -> a -> c 4 | on op f x y = f x `op` f y 5 | ``` 6 | 7 | Она принимает четыре аргумента: бинарный оператор с однотипными аргументами (типа b), 8 | функцию ```f :: a -> b```, возвращающую значение типа b, и два значения типа a. Функция on применяет f 9 | дважды к двум значениям типа a и передает результат в бинарный оператор. 10 | 11 | Используя on можно, например, записать функцию суммирования квадратов аргументов так: 12 | ```haskell 13 | sumSquares = (+) `on` (^2) 14 | ``` 15 | 16 | Функция multSecond, перемножающая вторые элементы пар, реализована следующим образом 17 | ```haskell 18 | multSecond = g `on` h 19 | g = undefined 20 | h = undefined 21 | ``` 22 | 23 | Напишите реализацию функций g и h. 24 | ``` 25 | GHCi> multSecond ('A',2) ('E',7) 26 | 14 27 | ``` 28 | Answer: 29 | 30 | ```haskell 31 | import Data.Function 32 | multSecond = g `on` h 33 | g x y = x * y 34 | h x = snd x 35 | ``` -------------------------------------------------------------------------------- /lection2/step2.1.9.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию on3, имеющую семантику, схожую с on, но принимающую в качестве первого аргумента трехместную функцию: 2 | 3 | ```haskell 4 | on3 :: (b -> b -> b -> c) -> (a -> b) -> a -> a -> a -> c 5 | on3 op f x y z = undefined 6 | ``` 7 | 8 | Например, сумма квадратов трех чисел может быть записана с использованием on3 так 9 | 10 | ``` 11 | GHCi> let sum3squares = (\x y z -> x+y+z) `on3` (^2) 12 | GHCi> sum3squares 1 2 3 13 | 14 14 | ``` 15 | 16 | Answer: 17 | 18 | ```haskell 19 | on3 :: (b -> b -> b -> c) -> (a -> b) -> a -> a -> a -> c 20 | on3 op f x y z = op (f x) (f y) (f z) 21 | ``` -------------------------------------------------------------------------------- /lection2/step2.2.3.md: -------------------------------------------------------------------------------- 1 | Функция одной переменной doItYourself выбирает наибольшее из переданного ей аргумента и числа 42, 2 | затем возводит результат выбора в куб и, наконец, вычисляет логарифм по основанию 2 от полученного числа. 3 | Эта функция реализована в виде: 4 | ```haskell 5 | doItYourself = f . g . h 6 | ``` 7 | Напишите реализации функций f, g и h. Постарайтесь сделать это в бесточечном стиле. 8 | 9 | ```haskell 10 | f = undefined 11 | g = undefined 12 | h = undefined 13 | ``` 14 | 15 | Answer: 16 | 17 | ```haskell 18 | doItYourself = f . g . h 19 | f x = logBase 2 x 20 | g x = x ^ 3 21 | h x = max 42 x 22 | ``` -------------------------------------------------------------------------------- /lection2/step2.2.5.md: -------------------------------------------------------------------------------- 1 | Сколько разных всегда завершающихся функций с типом ```a -> (a,b) -> a -> (b,a,a)``` можно реализовать? 2 | 3 | Answer: 4 | 5 | ``` 6 | 9 7 | ``` -------------------------------------------------------------------------------- /lection2/step2.2.7.md: -------------------------------------------------------------------------------- 1 | Какому известному вам библиотечному оператору, конструктору или функции эквивалентно выражение ```curry id```? 2 | 3 | Answer: 4 | 5 | ```haskell 6 | (,) 7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /lection2/step2.2.8.md: -------------------------------------------------------------------------------- 1 | Какому известному вам библиотечному оператору, конструктору или функции эквивалентно выражение 2 | ```uncurry (flip const)```? 3 | 4 | Answer: 5 | 6 | ```haskell 7 | snd 8 | ``` 9 | -------------------------------------------------------------------------------- /lection2/step2.2.9.md: -------------------------------------------------------------------------------- 1 | В модуле Data.Tuple стандартной библиотеки определена функция ```swap :: (a,b) -> (b,a)```, 2 | переставляющая местами элементы пары: 3 | ``` 4 | GHCi> swap (1,'A') 5 | ('A',1) 6 | ``` 7 | Эта функция может быть выражена в виде: 8 | ``` 9 | swap = f (g h) 10 | ``` 11 | где f, g и h — некоторые идентификаторы из следующего набора: 12 | ``` 13 | curry uncurry flip (,) const 14 | ``` 15 | Укажите через запятую подходящую тройку f,g,h. 16 | 17 | Answer: 18 | 19 | ``` 20 | uncurry,flip,(,) 21 | ``` -------------------------------------------------------------------------------- /lection2/step2.3.3.md: -------------------------------------------------------------------------------- 1 | Попробуйте, не используя GHCi, определить, какого контекста не хватает для того, чтобы выражение 2 | ```haskell 3 | True + False * False 4 | ``` 5 | могло бы быть типизировано. 6 | 7 | Answer: 8 | 9 | ``` 10 | Num Bool 11 | ``` -------------------------------------------------------------------------------- /lection2/step2.3.5.md: -------------------------------------------------------------------------------- 1 | Попробуйте, не используя GHCi или Hoogle, определить, какого контекста не хватает в типе функции 2 | ```haskell 3 | sort :: ? => [d] -> [d] 4 | ``` 5 | сортирующей переданной в нее список. Напишите выражение, которое должно стоять на месте знака вопроса. 6 | 7 | Answer: 8 | ```haskell 9 | Ord d 10 | ``` -------------------------------------------------------------------------------- /lection2/step2.3.7.md: -------------------------------------------------------------------------------- 1 | Реализуйте класс типов ```Printable```, предоставляющий один метод ```toString``` 2 | — функцию одной переменной, которая преобразует значение типа, являющегося представителем ```Printable```, 3 | в строковое представление. 4 | 5 | Сделайте типы данных ```Bool``` и ```()``` представителями этого класса типов, обеспечив следующее поведение: 6 | ``` 7 | GHCi> toString True 8 | "true" 9 | GHCi> toString False 10 | "false" 11 | GHCi> toString () 12 | "unit type" 13 | ``` 14 | 15 | Answer: 16 | 17 | ```haskell 18 | class Printable a where 19 | toString :: a -> String 20 | 21 | instance Printable Bool where 22 | toString True = "true" 23 | toString False = "false" 24 | 25 | instance Printable () where 26 | toString _ = "unit type" 27 | ``` -------------------------------------------------------------------------------- /lection2/step2.3.9.md: -------------------------------------------------------------------------------- 1 | Сделайте тип пары представителем класса типов ```Printable```, 2 | реализованного вами в предыдущей задаче, обеспечив следующее поведение: 3 | 4 | ``` 5 | GHCi> toString (False,()) 6 | "(false,unit type)" 7 | GHCi> toString (True,False) 8 | "(true,false)" 9 | ``` 10 | 11 | Примечание. Объявление класса типов ```Printable``` и представителей этого класса 12 | для типов ```()``` и ```Bool``` заново реализовывать не надо — они присутствуют в программе, вызывающей ваш код. 13 | 14 | Answer: 15 | 16 | ```haskell 17 | instance (Printable a, Printable b) => Printable (a,b) where 18 | toString p = "(" ++ ((toString.fst) p) ++ "," ++ ((toString.snd) p) ++ ")" 19 | ``` -------------------------------------------------------------------------------- /lection2/step2.4.3.md: -------------------------------------------------------------------------------- 1 | Пусть существуют два класса типов ```KnownToGork``` и ```KnownToMork```, 2 | которые предоставляют методы ```stomp (stab)``` и ```doesEnrageGork (doesEnrageMork)``` соответственно: 3 | ```haskell 4 | class KnownToGork a where 5 | stomp :: a -> a 6 | doesEnrageGork :: a -> Bool 7 | 8 | class KnownToMork a where 9 | stab :: a -> a 10 | doesEnrageMork :: a -> Bool 11 | ``` 12 | Класса типов ```KnownToGorkAndMork``` является расширением обоих этих классов, предоставляя дополнительно метод ```stompOrStab```: 13 | ```haskell 14 | class (KnownToGork a, KnownToMork a) => KnownToGorkAndMork a where 15 | stompOrStab :: a -> a 16 | ``` 17 | Задайте реализацию по умолчанию метода ```stompOrStab```, 18 | которая вызывает метод ```stomp```, если переданное ему значение приводит в 19 | ярость ```Морка```; вызывает ```stab```, если оно приводит в ярость Горка и вызывает сначала 20 | ```stab```, а потом ```stomp```, если оно приводит в ярость их обоих. Если не происходит ничего из 21 | вышеперечисленного, метод должен возвращать переданный ему аргумент. 22 | 23 | Answer: 24 | 25 | ```haskell 26 | class KnownToGork a where 27 | stomp :: a -> a 28 | doesEnrageGork :: a -> Bool 29 | 30 | class KnownToMork a where 31 | stab :: a -> a 32 | doesEnrageMork :: a -> Bool 33 | 34 | class (KnownToGork a, KnownToMork a) => KnownToGorkAndMork a where 35 | stompOrStab :: a -> a 36 | stompOrStab a | doesEnrageGork a && not (doesEnrageMork a) = stab a 37 | | doesEnrageMork a && not (doesEnrageGork a) = stomp a 38 | | doesEnrageMork a && doesEnrageGork a = (stomp.stab) a 39 | | otherwise = a 40 | ``` -------------------------------------------------------------------------------- /lection2/step2.4.5.md: -------------------------------------------------------------------------------- 1 | Имея функцию ```ip = show a ++ show b ++ show c ++ show d``` определите значения ```a, b, c, d``` 2 | так, чтобы добиться следующего поведения: 3 | 4 | ``` 5 | GHCi> ip 6 | "127.224.120.12" 7 | ``` 8 | 9 | Answer: 10 | 11 | ```haskell 12 | a = 127.2 13 | b = 24.1 14 | c = 20.1 15 | d = 2 16 | ``` -------------------------------------------------------------------------------- /lection2/step2.4.7.md: -------------------------------------------------------------------------------- 1 | Реализуйте класс типов 2 | ```haskell 3 | class SafeEnum a where 4 | ssucc :: a -> a 5 | spred :: a -> a 6 | ``` 7 | обе функции которого ведут себя как ```succ``` и ```pred``` 8 | стандартного класса ```Enum```, однако являются тотальными, 9 | то есть не останавливаются с ошибкой на наибольшем и наименьшем 10 | значениях типа-перечисления соответственно, а обеспечивают циклическое поведение. 11 | Ваш класс должен быть расширением ряда классов типов стандартной библиотеки, 12 | так чтобы можно было написать реализацию по умолчанию его методов, 13 | позволяющую объявлять его представителей без необходимости писать 14 | какой бы то ни было код. Например, для типа Bool должно быть достаточно написать строку 15 | ```haskell 16 | instance SafeEnum Bool 17 | ``` 18 | и получить возможность вызывать 19 | ``` 20 | GHCi> ssucc False 21 | True 22 | GHCi> ssucc True 23 | False 24 | ``` 25 | 26 | Answer: 27 | 28 | ```haskell 29 | class (Enum a, Bounded a, Eq a) => SafeEnum a where 30 | ssucc :: a -> a 31 | spred :: a -> a 32 | ssucc a | maxBound == a = minBound 33 | | otherwise = succ a 34 | spred a | minBound == a = maxBound 35 | | otherwise = pred a 36 | ``` -------------------------------------------------------------------------------- /lection2/step2.4.9.md: -------------------------------------------------------------------------------- 1 | Напишите функцию с сигнатурой: 2 | ```haskell 3 | avg :: Int -> Int -> Int -> Double 4 | ``` 5 | вычисляющую среднее значение переданных в нее аргументов: 6 | ``` 7 | GHCi> avg 3 4 8 8 | 5.0 9 | ``` 10 | 11 | Answer: 12 | 13 | ```haskell 14 | avg :: Int -> Int -> Int -> Double 15 | avg a b c = (fromIntegral (a + b + c)) / 3 16 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.11.md: -------------------------------------------------------------------------------- 1 | В каких из перечисленных ниже функций seq предотвратит образование всех thunk’ов: 2 | ```haskell 3 | foo x = x `seq` x 4 | 5 | bar 0 f = f 6 | bar x f = let f' = \a -> f (x + a) 7 | x' = x - 1 8 | in f' `seq` x' `seq` bar x' f' 9 | 10 | baz 0 (x, y) = x + y 11 | baz n (x, y) = let x' = x + 1 12 | y' = y - 1 13 | p = (x', y') 14 | n' = n - 1 15 | in p `seq` n' `seq` baz n' p 16 | 17 | quux 0 (x, y) = x + y 18 | quux n (x, y) = let x' = x + 1 19 | y' = y - 1 20 | p = (x', y') 21 | n' = n - 1 22 | in x' `seq` y' `seq` n' `seq` quux n' p 23 | ``` 24 | 25 | Answer: 26 | 27 | ``` 28 | foo 29 | bar 30 | baz 31 | *quux 32 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.13.md: -------------------------------------------------------------------------------- 1 | Ниже определены функции mySum и goSum. Вызов goSum может выглядеть, к примеру, так: ```goSum 15```. 2 | Выберите верные утверждения, описывающие процесс вычисления подобного выражения. 3 | 4 | ```haskell 5 | mySum acc 0 = acc 6 | mySum (result, ()) n = (mySum $! (result + n, ())) $ n - 1 7 | 8 | goSum = mySum (0, ()) 9 | ``` 10 | 11 | Answer: 12 | 13 | ``` 14 | В первом аргументе функции mySum не будут накапливаться отложенные вычисления, так как при рекурсивных вызовах используется оператор $!$!. 15 | В первом аргументе функции mySum не будут накапливаться отложенные вычисления, так как он будет находиться в слабой головной нормальной форме. 16 | *В первом аргументе функции mySum будут накапливаться отложенные вычисления. 17 | Во втором аргументе функции mySum будут накапливаться отложенные вычисления из-за того, что его передача при рекурсивном вызове происходит с помощью оператора $$ а не $!$!. 18 | *Во втором аргументе функции mySum не будут накапливаться отложенные вычисления, так как при каждом рекурсивном вызове происходит сопоставление с 0. 19 | Во втором аргументе функции mySum не будут накапливаться отложенные вычисления, так как минус - примитивная операция. 20 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.3.md: -------------------------------------------------------------------------------- 1 | Предположим, что стандартные функции определены следующим образом: 2 | ```haskell 3 | id x = x 4 | const x y = x 5 | max x y = if x <= y then y else x 6 | infixr 0 $ 7 | f $ x = f x 8 | ``` 9 | Сколько редексов имеется в следующем выражении 10 | ```haskell 11 | const $ const (4 + 5) $ max 42 12 | ``` 13 | 14 | Answer: 15 | 16 | ``` 17 | 3 18 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.5.md: -------------------------------------------------------------------------------- 1 | Сколько шагов редукции потребуется, чтобы вычислить значение функции ```value```, 2 | если используется ленивая стратегия вычислений с механизмом разделения? 3 | ```haskell 4 | bar x y z = x + y 5 | foo a b = bar a a (a + b) 6 | value = foo (3 * 10) (5 - 2) 7 | ``` 8 | Примечание. Подстановку тела функции value вместо value не считайте. 9 | 10 | Answer: 11 | 12 | ``` 13 | 4 14 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.7.md: -------------------------------------------------------------------------------- 1 | Отметьте функции, которые не могут привести к расходимости ни на каком корректном наборе аргументов. 2 | ```haskell 3 | foo a = a 4 | bar = const foo 5 | baz x = const True 6 | quux = let x = x in x 7 | corge = 10 8 | grault x 0 = x 9 | grault x y = x 10 | garply = grault 'q' 11 | waldo = foo 12 | ``` 13 | 14 | Answer: 15 | 16 | ```haskell 17 | * baz 18 | waldo 19 | grault 20 | * corge 21 | foo 22 | bar 23 | quux 24 | garply 25 | ``` -------------------------------------------------------------------------------- /lection2/step2.5.9.md: -------------------------------------------------------------------------------- 1 | Какие из выражений ниже не находятся в нормальной форме, но находятся в слабой головной нормальной форме? 2 | 3 | Answer: 4 | 5 | ``` 6 | * (+) (2 * 3 * 4) 7 | \x -> x 8 | * [undefined, 4 + 5, -1] 9 | 3 10 | * (undefined,) 11 | fst (1,0) 12 | ``` -------------------------------------------------------------------------------- /lection2/step2.6.3.md: -------------------------------------------------------------------------------- 1 | Что произойдет при попытке загрузить данный модуль в GHCi? 2 | ```haskell 3 | module Test where 4 | import Data.List hiding (union) 5 | import Data.Set 6 | 7 | myUnion [] ys = ys 8 | myUnion xs ys = union xs ys 9 | ``` 10 | 11 | Answer: 12 | 13 | ``` 14 | Произойдет ошибка из-за неопределенности при выборе функции 15 | * Произойдет ошибка из-за несовпадения типа аргумента и ожидаемого типа функции 16 | Все пройдет нормально 17 | ``` -------------------------------------------------------------------------------- /lection2/step2.6.5.md: -------------------------------------------------------------------------------- 1 | Пусть модуль ```Foo``` содержит следующий код: 2 | ```haskell 3 | module Foo (a, b) where 4 | 5 | a = undefined 6 | b = undefined 7 | c = undefined 8 | ``` 9 | а модуль ```Bar```: 10 | ```haskell 11 | module Bar (a, d) where 12 | 13 | import Foo (a, b) 14 | 15 | d = undefined 16 | ``` 17 | 18 | Отметьте функции, доступные для использования после загрузки в модуле ```Baz``` со следующим кодом: 19 | ```haskell 20 | module Baz where 21 | 22 | import Bar 23 | ``` 24 | 25 | Answer: 26 | 27 | ``` 28 | c 29 | * d 30 | b 31 | * a 32 | ``` --------------------------------------------------------------------------------