- •Оглавление
- •От автора
- •Структура
- •Пояснения и обозначения
- •Демонстрация кунг-фу
- •Теория Основные понятия и типы данных
- •Кортежи
- •Функции, операторы
- •Полиморфные типы данных
- •Чтение сигнатур типов
- •Простейшие функции и операторы
- •Арифметические функции
- •Логические функции
- •Списочные функции
- •Кортежные функции
- •Создание своих функций
- •Способ 1. Определение функции как выражения от параметров:
- •Способ 2. Несколько определений одной функции:
- •Способ 3. Определение функции через синоним:
- •Способ 4. Лямбда функция (анонимная функция):
- •Способ 5. Частичное применение функции:
- •Образцы и сопоставление с образцом
- •Синтаксический хлеб и синтаксический сахар
- •Условия и ограничения
- •Локальные определения
- •Двумерный синтаксис
- •Арифметические последовательности
- •Замыкания списков
- •Функциональное мышление
- •Рекурсия как основное средство
- •Ручная редукция выражений
- •Думаем функционально, шаг раз
- •Думаем функционально, шаг два: аккумуляторы
- •Реализация простейших списочных и прочих функций
- •Думаем функционально, шаг три: хвостовая рекурсия
- •Еще раз о рекурсии
- •Полезные хитрости языка
- •Ленивые вычисления и строгие функции
- •Бесконечные списки
- •Функция show
- •Совсем немного о классах
- •Функция read
- •Функция error
- •Побочные эффекты и функция trace
- •Функции высших порядков
- •Мотивация
- •Функция map
- •Функция filter
- •Композиция функций
- •Функция foldr
- •Функция foldl
- •Свертки: разбор полетов
- •Выявление общей функциональности
- •Стандартные функции высших порядков
- •Еще немного про строгие функции
- •Создание своих типов данных
- •Простые перечислимые типы данных
- •Контейнеры
- •О сравнении, отображении и прочих стандартных операциях
- •Параметрические типы данных
- •Сложные типы данных
- •Тип данных Maybe
- •Рекурсивные типы данных: списки
- •Рекурсивные типы данных: деревья
- •Ввод-вывод
- •Простейший ввод-вывод
- •Объяснение кухни
- •Пример программы, производящей нетривиальное преобразование текстового файла
- •Пример решения задачи: Поиск в пространстве состояний
- •Через массивы и последовательность промежуточных состояний
- •Решение для тех, кто не хочет разбираться сам
- •Через списки, лог истории и уникальную очередь
- •Решение для тех, кто не хочет разбираться сам
- •Задачник
- •Пояснения и обозначения
- •Лабораторная работа 1 Простейшие функции
- •Простейшие логические функции
- •Простейшие списочные функции
- •Лабораторная работа 2 Символьные функции
- •Простейшие кортежные функции
- •Теоретико-множественные операции
- •Сортировка
- •Арифметические последовательности
- •Генераторы списков
- •Лабораторная работа 4 Бесконечные списки
- •Ввод-вывод
- •Нетривиальные функции
- •Лабораторная работа 5 Простые числа и факторизация
- •Деревья
- •Деревья вычислений
- •Дополнительные задания для самостоятельной работы Задания с Project Euler
- •Простейший инструментарий Установка WinHugs и начало работы
- •Работа с интерпретатором WinHugs в интерактивном режиме
- •Команды интерпретатору
- •Работа с модулями
- •Список рекомендуемой литературы и электронных ресурсов
Пояснения и обозначения
Вот таким шрифтом обозначаются куски кода, имена функций и сигнатуры типа.
Вот таким образом оформлены замечания, дополнения и заметки на полях.
Демонстрация кунг-фу
Классика жанра. В качестве мотивации студентов к изучению Haskell (кроме, конечно, демонстрации пряника зачетных единиц и кнута в виде списка отчисленных за прошлый семестр) обычно приводят небольшие кусочки кода, которые должны поразить своей красотой, краткостью и мощностью. С краткостью и мощностью обычно проблем нет. Вот быстрая сортировка любого списка:
qsort [] = []
qsort (x:xs) = qsort [y | y <- xs, y <= x]
++ [x] ++
qsort [y | y <- xs, y > x]
Вот бесконечный список чисел Фибоначчи:
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
или так:
fibbs = 1 : 1 : next fibbs where
next (x:y:xs) = x + y : next (y:xs)
или так:
fibbbs = next 0 1 where
next x y = y : next y (x+y)
Вот простые числа:
primes = map head $ iterate sieve [2..] where
sieve (x:xs) = [y | y <-xs, y `mod` x /= 0]
или так:
primes = 2 :
filter (\x -> all (\p -> x `mod` p /= 0) $
takeWhile (\p -> p^2 <= x) primes)
[3..]
А вот создание идеально сбалансированного бинарного поискового дерева:
data Ord a => SearchTree a =
Empty | Branches a (SearchTree a) (SearchTree a)
deriving Show
putVal x Empty = Branches x Empty Empty
putVal x (Branches v l r)
| x > v = Branches v l (putVal x r)
| otherwise = Branches v (putVal x l) r
list2tree xs = foldl (flip putVal) Empty xs
height Empty = 0
height (Branches v l r) = max (height l) (height r) + 1
stepr (Branches v l@(Branches lv ll lr) r)
| height lr > height ll =
stepr (Branches v (stepl l) r)
| otherwise =
(Branches lv ll (Branches v lr r))
stepl (Branches v l r@(Branches rv rl rr))
| height rl > height rr =
stepl (Branches v l (stepr r))
| otherwise =
(Branches rv (Branches v l rl) rr)
balance Empty = Empty
balance t@(Branches v l r) =
balance' (Branches v (balance l) (balance r)) where
balance' t@(Branches v l r)
| height l - height r > 1 =
balance $ stepr (Branches v l r)
| height r - height l > 1 =
balance $ stepl (Branches v l r)
| otherwise = t
Так как студенты обычно решают эти задачи на первом-втором курсе в рамках изучения программирования и стандартных алгоритмов, они помнят, сколько кода на C++ требует сортировка или простые числа, и сколько мучений с поворотами и указателями возникает при работе с идеально сбалансированными деревьями. Может быть, они даже помнят, как приходилось думать, сколько памяти выделять под массив простых чисел, и поэтому впечатляются бесконечным списком чисел Фибоначчи или списком простых чисел.
Однако настоящую красоту функционального программирования, красоту идей и смыслов, невозможно продемонстрировать кодом на неизвестном языке. И радостно автору становится именно тогда, когда удается найти такое объяснение, благодаря которому еще у кого-нибудь загораются восхищением глаза.