
- •Оглавление
- •От автора
- •Структура
- •Пояснения и обозначения
- •Демонстрация кунг-фу
- •Теория Основные понятия и типы данных
- •Кортежи
- •Функции, операторы
- •Полиморфные типы данных
- •Чтение сигнатур типов
- •Простейшие функции и операторы
- •Арифметические функции
- •Логические функции
- •Списочные функции
- •Кортежные функции
- •Создание своих функций
- •Способ 1. Определение функции как выражения от параметров:
- •Способ 2. Несколько определений одной функции:
- •Способ 3. Определение функции через синоним:
- •Способ 4. Лямбда функция (анонимная функция):
- •Способ 5. Частичное применение функции:
- •Образцы и сопоставление с образцом
- •Синтаксический хлеб и синтаксический сахар
- •Условия и ограничения
- •Локальные определения
- •Двумерный синтаксис
- •Арифметические последовательности
- •Замыкания списков
- •Функциональное мышление
- •Рекурсия как основное средство
- •Ручная редукция выражений
- •Думаем функционально, шаг раз
- •Думаем функционально, шаг два: аккумуляторы
- •Реализация простейших списочных и прочих функций
- •Думаем функционально, шаг три: хвостовая рекурсия
- •Еще раз о рекурсии
- •Полезные хитрости языка
- •Ленивые вычисления и строгие функции
- •Бесконечные списки
- •Функция show
- •Совсем немного о классах
- •Функция read
- •Функция error
- •Побочные эффекты и функция trace
- •Функции высших порядков
- •Мотивация
- •Функция map
- •Функция filter
- •Композиция функций
- •Функция foldr
- •Функция foldl
- •Свертки: разбор полетов
- •Выявление общей функциональности
- •Стандартные функции высших порядков
- •Еще немного про строгие функции
- •Создание своих типов данных
- •Простые перечислимые типы данных
- •Контейнеры
- •О сравнении, отображении и прочих стандартных операциях
- •Параметрические типы данных
- •Сложные типы данных
- •Тип данных Maybe
- •Рекурсивные типы данных: списки
- •Рекурсивные типы данных: деревья
- •Ввод-вывод
- •Простейший ввод-вывод
- •Объяснение кухни
- •Пример программы, производящей нетривиальное преобразование текстового файла
- •Пример решения задачи: Поиск в пространстве состояний
- •Через массивы и последовательность промежуточных состояний
- •Решение для тех, кто не хочет разбираться сам
- •Через списки, лог истории и уникальную очередь
- •Решение для тех, кто не хочет разбираться сам
- •Задачник
- •Пояснения и обозначения
- •Лабораторная работа 1 Простейшие функции
- •Простейшие логические функции
- •Простейшие списочные функции
- •Лабораторная работа 2 Символьные функции
- •Простейшие кортежные функции
- •Теоретико-множественные операции
- •Сортировка
- •Арифметические последовательности
- •Генераторы списков
- •Лабораторная работа 4 Бесконечные списки
- •Ввод-вывод
- •Нетривиальные функции
- •Лабораторная работа 5 Простые числа и факторизация
- •Деревья
- •Деревья вычислений
- •Дополнительные задания для самостоятельной работы Задания с Project Euler
- •Простейший инструментарий Установка WinHugs и начало работы
- •Работа с интерпретатором WinHugs в интерактивном режиме
- •Команды интерпретатору
- •Работа с модулями
- •Список рекомендуемой литературы и электронных ресурсов
Решение для тех, кто не хочет разбираться сам
Приведем здесь наше новое решение целиком, для тех, кому просто интересно, как оно может выглядеть:
module Boat where
import List
-- объект
data Item = Wolf | Goat | Cabbage
deriving (Show, Eq, Ord)
-- положение: где человек-лодка +
-- кто на левом берегу +
-- кто на правом + лог истории
data Position =
L [Item] [Item] String | R [Item] [Item] String
deriving Show
-- два положения одинаковые,
-- если все одинаковое, кроме лога
instance Eq Position where
(==) (L l1 r1 _) (L l2 r2 _) =
l1 == l2 && r1 == r2
(==) (R l1 r1 _) (R l2 r2 _) =
l1 == l2 && r1 == r2
_ == _ = False
-- начальная и целевая позиция
startPosition = L [Wolf, Goat, Cabbage] [] ""
goalPosition = R [] [Wolf, Goat, Cabbage] ""
-- неправильная компания
wrongCompany c =
null ([Goat, Cabbage] \\ c) ||
null ([Goat, Wolf] \\ c)
-- неправильная позиция: без контроля человека остается плохая компания
wrongPosition (L left right _) = wrongCompany right
wrongPosition (R left right _) = wrongCompany left
-- шаг переправы с берега на берег с кем-нибудь: какие варианты можно получить
step (L left right hist) =
[R left right (hist++"Move Right ")] ++
[R (left \\ [who]) (sort $ who:right)
(hist++"Take "++show who++" Right ")
| who <- left]
step (R left right hist) =
[L left right (hist++"Move Left ")] ++
[L (sort $ who:left) (right \\ [who])
(hist++"Take "++show who++" Left ")
| who <- right]
-- очередь поиска
queue old [] = old
queue old (p:ps) =
queue (p:old) (nub $ ps ++ candidates) where
candidates = filter (not.wrongPosition)
(step p) \\ old
-- запускаем поиск по очереди и находим в нем решение
solution = head $
dropWhile (/= goalPosition) $
queue [] [startPosition]
Кто дочитал до этого места и знает, чему равен xyz, может обращаться ко мне за призом. Всего хорошего!
Задачник
Приведенный ниже задачник построен в форме пяти лабораторных работ, каждая из которых объединяет набор заданий на написание функций, объединенных общей тематикой. Подразумевается, что задачи будут выполняться друг за другом параллельно изучению теоретической части – или сразу после ее изучения.
Пояснения и обозначения
Как правило, в большинстве заданий приведены названия уже существующих стандартных функций. Требуется запросить в интерпретаторе тип функций, создать примеры входных данных для них и убедиться, что функции работают именно так, как вы представляете. В заданиях второго типа требуется написать замену стандартной функции, или же написать функцию, аналогичной которой нет среди стандартных. Такие функции лучше писать с постфиксом My, чтобы имена их не пересекались со стандартными, например, headMy. После написания такой функции, заменяющей стандартную, можно в дальнейшем пользоваться стандартной.
В большинстве случаев, приводимые имена функций совпадают со стандартными именами функций, делающих то же самое в стандартных модулях. Для функций с постфиксом My не имеется стандартных аналогов.
Вот таким шрифтом обозначаются куски кода, имена функций и сигнатуры типа.
Вот таким образом оформлены дополнительные задания, выполнять которые необходимо только тем, кто хочет научиться чуть большему, чем остальные. Остальные могут их пропускать.