мета-данные страницы
Загрузка не удалась. Возможно, проблемы с правами доступа?
Различия
Показаны различия между двумя версиями страницы.
Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
haskell [17/07/2018 17:36] – [3.7 Определитель списков и диапазоны] Владимир Власов | haskell [05/09/2024 19:52] (текущий) – Владимир Власов | ||
---|---|---|---|
Строка 25: | Строка 25: | ||
- [[http:// | - [[http:// | ||
- [[http:// | - [[http:// | ||
- | - [[http://dev.by/blogs/ | + | - [[https://events.dev.by/lenta/ |
- [[http:// | - [[http:// | ||
- [[https:// | - [[https:// | ||
- [[http:// | - [[http:// | ||
- [[http:// | - [[http:// | ||
+ | - [[https:// | ||
- | < | ||
- | <!-- http:// | ||
- | </ | ||
===== Урок 1. Знакомство с интерпретатором ghci ===== | ===== Урок 1. Знакомство с интерпретатором ghci ===== | ||
Строка 40: | Строка 38: | ||
**Полезные команды** в ghci: | **Полезные команды** в ghci: | ||
- | :q -- выйти из оболочки; | + | '' |
- | :l <имя программы> | + | '' |
- | :r -- перегрузить текущий модуль; | + | '' |
- | :t <имя функции> | + | '' |
- | :i <имя функции> | + | '' |
Кроме того, надо знать, что выражения в оболочке интерпретатора можно сразу вычислять. | Кроме того, надо знать, что выражения в оболочке интерпретатора можно сразу вычислять. | ||
- | Наберем 2 + 2 и нажмем Enter, или наберем abs (-2) и нажмем Enter, и т.д. | + | Наберем 2 + 2 и нажмем Enter, или наберем |
Новые функции (пользовательские) можно задавать, | Новые функции (пользовательские) можно задавать, | ||
Строка 58: | Строка 56: | ||
> let {f :: Int -> Int; f n = n * 2} | > let {f :: Int -> Int; f n = n * 2} | ||
</ | </ | ||
+ | |||
+ | Отметим, | ||
Многострочные записи делают следующим образом: | Многострочные записи делают следующим образом: | ||
Строка 76: | Строка 76: | ||
</ | </ | ||
- | Для просмотра тех или иных значений функции f можно попробовать набрать f 4, а для просмотра произвольного значения foo набрать show foo. | + | Для просмотра тех или иных значений функции |
+ | |||
+ | Дополнительно отметим, | ||
Строка 90: | Строка 92: | ||
и мы уже вряд ли сможем посчитать факториал с аргументом более 31. | и мы уже вряд ли сможем посчитать факториал с аргументом более 31. | ||
- | Остальной код задан в виде уравнений, | + | Остальной код задан в виде уравнений, |
- | Возможно использование рекурсии при описании функции. При вызове функций им передается | + | |
<code haskell> | <code haskell> | ||
Строка 136: | Строка 137: | ||
В Haskell возможно описание вычисления функции в | В Haskell возможно описание вычисления функции в | ||
зависимости от условий в более-менее традиционном ключе, для чего | зависимости от условий в более-менее традиционном ключе, для чего | ||
- | присутствуют операторы if и case. Однако, | + | присутствуют операторы |
аналогичных операторов в императивных языках. (Правильнее их называть | аналогичных операторов в императивных языках. (Правильнее их называть | ||
- | выражениями с использованием case- и if-then-else-конструкций) | + | выражениями с использованием |
< | < | ||
Строка 147: | Строка 148: | ||
</ | </ | ||
- | Оператор if предназначен для ветвления вычислительного процесса в | + | Ключевое слово '' |
- | зависимости от условия булевского типа. Части then и else обязательны, | + | зависимости от условия булевского типа. Части |
в отличие от императивного аналога задают не порядок действий, | в отличие от императивного аналога задают не порядок действий, | ||
- | которые возвращают результат для задаваемой функции. Данный оператор | + | которые возвращают результат для задаваемой функции. Данное |
- | частным, | + | частным, |
Иными словами, | Иными словами, | ||
Строка 167: | Строка 168: | ||
</ | </ | ||
- | Рассмотрим более сложные примеры с case-выражениями: | + | Рассмотрим более сложные примеры с '' |
< | < | ||
Строка 182: | Строка 183: | ||
</ | </ | ||
- | Последний пример является комбинацией использования case-выражения с << | + | Последний пример является комбинацией использования |
для предотвращения применения функции для отрицательных аргументов. | для предотвращения применения функции для отрицательных аргументов. | ||
Стоит также упомянуть, | Стоит также упомянуть, | ||
- | рассматривать как упрощенную запись с соответствующими case-выражениями. | + | рассматривать как упрощенную запись с соответствующими |
- | **__Упражнение__.** Задать функцию sign(x) из предыдущего упражнения, | + | **__Упражнение__.** Задать функцию |
==== 2.2 Карринг и лямбда-абстракция ==== | ==== 2.2 Карринг и лямбда-абстракция ==== | ||
- | **Карринг.** Отметим, | + | **Карринг.** Отметим, |
Для чего нужен карринг и такие сложности? | Для чего нужен карринг и такие сложности? | ||
- | Рассмотрим выше заданную функцию | + | Рассмотрим выше заданную функцию |
<code haskell> | <code haskell> | ||
Строка 203: | Строка 204: | ||
</ | </ | ||
- | Тогда мы легко можем задать частный случай сложения, | + | Тогда мы легко можем задать частный случай сложения, |
<code haskell> | <code haskell> | ||
Строка 233: | Строка 234: | ||
Если мы подставим в качестве аргумента 4, то увидим разницу значений | Если мы подставим в качестве аргумента 4, то увидим разницу значений | ||
- | функций | + | функций |
- | В следующем, | + | В следующем, |
различными способами (можно запустить функции для проверки с аргументами 4 и 5): | различными способами (можно запустить функции для проверки с аргументами 4 и 5): | ||
Строка 252: | Строка 253: | ||
качестве второго аргумента. Например, | качестве второго аргумента. Например, | ||
готовую функцию, | готовую функцию, | ||
- | в ghci наберите show l1 и show l2. | + | в '' |
<code haskell> | <code haskell> | ||
- | l1 = map abs [-1, 2, -4.2] | + | l1 = map abs [(-1), 2, (-4.2)] |
- | l2 = map (\x -> if x >= 0 then x else negate x) [-1, 2, -4.2] | + | l2 = map (\x -> if x >= 0 then x else negate x) [(-1), 2, (-4.2)] |
</ | </ | ||
Строка 262: | Строка 263: | ||
<code haskell> | <code haskell> | ||
- | l3 = map ((\x -> if x >= 0 then x else negate x)::(Double -> Double) [-1, 2, -4.2] | + | l3 = |
+ | | ||
+ | then x | ||
+ | else negate x)::(Double -> Double)) | ||
+ | | ||
</ | </ | ||
- | |||
==== 2.3 Замыкания (локальные определения)==== | ==== 2.3 Замыкания (локальные определения)==== | ||
Строка 286: | Строка 290: | ||
применении они очень похожи! | применении они очень похожи! | ||
- | < | + | < |
roots' a b c = (x1,x2) where | roots' a b c = (x1,x2) where | ||
d = b^2 - 4*a*c | d = b^2 - 4*a*c | ||
Строка 298: | Строка 302: | ||
При упрощённом подходе мы не отслеживаем случаи, | При упрощённом подходе мы не отслеживаем случаи, | ||
- | < | + | < |
roots' a b c | ((a == 0) && (b == 0)) = error "No roots at all!" | roots' a b c | ((a == 0) && (b == 0)) = error "No roots at all!" | ||
| ((a == 0) && (b /= 0)) = (x,x) -- let x = -c/b in (x, | | ((a == 0) && (b /= 0)) = (x,x) -- let x = -c/b in (x, | ||
Строка 379: | Строка 383: | ||
</ | </ | ||
- | Вот версия более простого и понятного примера: | + | < |
+ | Как показали дальнейшие изыскания, | ||
+ | [[https:// | ||
+ | < | ||
+ | Prelude> :set -XMonomorphismRestriction | ||
+ | Prelude> let x = 2 | ||
+ | Prelude> x + 2.0 | ||
+ | |||
+ | < | ||
+ | * No instance for (Fractional Integer) | ||
+ | arising from the literal `2.0' | ||
+ | ... | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | Вот версия более простого и понятного примера, без странностей ограничения мономорфизма: | ||
<code haskell> | <code haskell> | ||
Строка 390: | Строка 410: | ||
In an equation for `it': it = x + y | In an equation for `it': it = x + y | ||
</ | </ | ||
- | В языках типа Си это соответствовало бы объявлению и инициализации переменных типа | + | В языках типа Си это соответствовало бы объявлению и инициализации переменных типа |
==== 2.6 Использование монады состояния==== | ==== 2.6 Использование монады состояния==== | ||
Пока без комментариев, | Пока без комментариев, | ||
- | < | + | < |
import Control.Monad.State | import Control.Monad.State | ||
- | fact' :: Integer -> State Integer Integer -- тип состояния - Int, тип результата - тоже | + | fact' :: Integer -> State Integer Integer |
+ | -- тип состояния - Integer, тип результата - тоже | ||
fact' 0 = do | fact' 0 = do | ||
acc <- get -- получаем накопленный результат | acc <- get -- получаем накопленный результат | ||
Строка 407: | Строка 428: | ||
fact' (n - 1) -- продолжаем вычисление факториала | fact' (n - 1) -- продолжаем вычисление факториала | ||
- | -- fact :: Int -> Int | + | -- fact :: Integer |
fact n = fst $ runState (fact' n) 1 -- начальное значение состояния = 1 | fact n = fst $ runState (fact' n) 1 -- начальное значение состояния = 1 | ||
</ | </ | ||
Строка 415: | Строка 436: | ||
**__Задания к уроку__** | **__Задания к уроку__** | ||
- | 1. Используя примеры из урока, написать код и исполнить его в ghci, проверить тип полученных функций. | + | 1. Используя примеры из урока, написать код и исполнить его в '' |
- | 2. Сделать тоже самое в отдельном файл и загрузить его в ghci с помощью команды :l. | + | 2. Сделать тоже самое в отдельном файл и загрузить его в '' |
- | 3. Написать код для функций | + | 3. Написать код для функций |
===== Урок 3. Списки как типы ===== | ===== Урок 3. Списки как типы ===== | ||
Строка 433: | Строка 454: | ||
(везде ниже '' | (везде ниже '' | ||
- | * '' | + | * '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
* '' | * '' | ||
- | * '' | + | * '' |
==== 3.2 Добавление к списку === | ==== 3.2 Добавление к списку === | ||
Строка 594: | Строка 615: | ||
* '' | * '' | ||
* '' | * '' | ||
- | * ''< | + | * ''< |
* '' | * '' | ||
* '' | * '' | ||
Строка 699: | Строка 720: | ||
</ | </ | ||
+ | |||
+ | Более детально об импорте модулей можно прочитать тут: [[https:// | ||
==== 4.2 Экспорт модулей ==== | ==== 4.2 Экспорт модулей ==== | ||
Строка 1046: | Строка 1069: | ||
(<>) :: MyAlg -> MyAlg -> MyAlg | (<>) :: MyAlg -> MyAlg -> MyAlg | ||
O <> x = x | O <> x = x | ||
- | n <>x = next (prev n <> x) | + | n <> x = next (prev n <> x) |
(><) :: MyAlg -> MyAlg -> MyAlg | (><) :: MyAlg -> MyAlg -> MyAlg | ||
Строка 1156: | Строка 1179: | ||
- | **Задание.** Создать собственный класс Logic с операциями &&&, | + | **Задание.** Создать собственный класс Logic с операциями |
Формально класс описывается следующим образом: | Формально класс описывается следующим образом: | ||
Строка 1177: | Строка 1200: | ||
<code haskell> | <code haskell> | ||
- | infixl 7 (&&& | + | infixl 7 &&& |
- | infixl 5 (|||) | + | infixl 5 ||| |
</ | </ | ||
Строка 1253: | Строка 1276: | ||
</ | </ | ||
- | Этот код уже не слишком тривиален (что видно по обилию " | + | Этот код уже не слишком тривиален (что видно по обилию " |
Заметим, | Заметим, | ||
Строка 1273: | Строка 1296: | ||
</ | </ | ||
- | Для многострочных программ нам необходимо использовать ключевой слово < | + | Для многострочных программ нам необходимо использовать ключевое слово < |
Вот как осуществляется получение аргументов командной строки в самом простом случае: | Вот как осуществляется получение аргументов командной строки в самом простом случае: | ||
Строка 1313: | Строка 1336: | ||
==== Урок 6.2 Взаимодействие с STDIN-STDOUT ==== | ==== Урок 6.2 Взаимодействие с STDIN-STDOUT ==== | ||
- | Список базовых функций ввода-вывода может быть найден тут: [[http://www.haskell.org/ | + | Список базовых функций ввода-вывода может быть найден тут: [[https://downloads.haskell.org/ |
или на русском языке тут: | или на русском языке тут: | ||
[[http:// | [[http:// | ||
Строка 1524: | Строка 1547: | ||
writeFile " | writeFile " | ||
</ | </ | ||
- | Здесь " | + | Здесь " |
Работа с " | Работа с " | ||
Строка 1531: | Строка 1554: | ||
==== 6.6 Запуск и компиляция ==== | ==== 6.6 Запуск и компиляция ==== | ||
- | Запуск подготовленных указанным выше способом возможен разными путями. | + | Запуск подготовленных указанным выше способом |
Во-первых, | Во-первых, | ||
Строка 1571: | Строка 1594: | ||
<code haskell> | <code haskell> | ||
- | data Maybe a = Nothing | Just a | + | data Maybe a = Nothing | Just a deriving (Eq, Ord) |
</ | </ | ||
(Напомним, | (Напомним, | ||
Строка 1581: | Строка 1604: | ||
</ | </ | ||
- | Полиморфные типы похожи на контейнеры, | + | Полиморфные типы похожи на контейнеры, |
Теперь, | Теперь, | ||
Строка 2584: | Строка 2607: | ||
то не распозналось.. Если элементы во входном списке еще остались, | то не распозналось.. Если элементы во входном списке еще остались, | ||
- | Ниже применяем полученные функции для создания парсера | + | Ниже применяем полученные функции для создания парсера |
<code haskell> | <code haskell> | ||
parse teststr = if (mss == " | parse teststr = if (mss == " |