Изучай Erlang во имя добра!
Покупка
Издательство:
ДМК Пресс
Автор:
Хеберт Фред
Перевод:
Литовченко Д.
Год издания: 2019
Кол-во страниц: 688
Дополнительно
Вид издания:
Практическое пособие
Уровень образования:
Дополнительное образование
ISBN: 978-5-97060-571-4
Артикул: 712461.02.99
Доступ онлайн
В корзину
Усеянная беспечными иллюстрациями и смесью развлекательных и практических примеров программ, книга «Изучай Erlang во имя добра!» является отличным пунктом отправления в иногда безумный, но всегда восхитительный мир Erlang. Вероятно, вас привело к Erlang обещание конкурентности или параллелизма. Возможно, это аспект языка, касающийся распределённых вычислений, а может быть, необычный подход к устойчивости против сбоев. Одним из величайших препятствий на пути изучения Erlang является не столько то, что идеям его свойственна сложность, но и то, что они сильно отличаются от идей большинства других языков, которые вам встречались. Переменные в Erlang не переменны. Вам не следует программировать в ожидании ошибки. Процессы действительно очень дёшевы, и вы можете иметь тысячи их одновременно, даже миллионы, если вам так захочется. Ох, и потом этот странный синтаксис. Erlang совершенно не похож Hajava; нет ни методов, ни классов, ни объектов. И, обождите... знак равенства вовсе не означает «равно»... Издание предназначено как для начинающих изучать Erlang, так и для более опытных разработчиков. Даже в том случае, если читатель очень хорошо знаком с Erlang, книга сможет стать справочником и даже научить чему-то новому.
Тематика:
ББК:
УДК:
ОКСО:
- ВО - Бакалавриат
- 09.03.01: Информатика и вычислительная техника
- 09.03.02: Информационные системы и технологии
- 09.03.03: Прикладная информатика
- 09.03.04: Программная инженерия
ГРНТИ:
Скопировать запись
Фрагмент текстового слоя документа размещен для индексирующих роботов.
Для полноценной работы с документом, пожалуйста, перейдите в
ридер.
Фред Хеберт Изучай Erlang во имя добра! !!!
Learn You Some Erlang for Great Good! San Francisco Fred Hebert
Изучай Erlang во имя добра! Москва, 2019 Фред Хеберт
УДК 004.432.42Erlang ББК 32.973.28-018.1 Хеберт, Фред. Изучай Erlang во имя добра! / Пер. с англ. Литовченко Д. — М.: ДМК Пресс, 2019. — 688 с.: ил. ISBN 978-5-97060-571-4 Усеянная беспечными иллюстрациями и смесью развлекательных и практических примеров программ, книга «Изучай Erlang во имя добра!» является отличным пунктом отправления в иногда безумный, но всегда восхитительный мир Erlang. Издание предназначено как для начинающих изучать Erlang, так и для более опытных разработчиков. Даже в том случае, если читатель очень хорошо знаком с Erlang, книга сможет стать справочником и даже научить чему-то новому. Вероятно, вас привело к Erlang обещание конкурентности или параллелизма. Возможно, это аспект языка, касающийся распределённых вычислений, а может быть, необычный подход к устойчивости против сбоев. Одним из величайших препятствий на пути изучения Erlang является не столько то, что идеям его свойственна сложность, но и то, что они сильно отличаются от идей большинства других языков, которые вам встречались. Переменные в Erlang не переменны. Вам не следует программировать в ожидании ошибки. Процессы действительно очень дёшевы, и вы можете иметь тысячи их одновременно, даже миллионы, если вам так захочется. Ох, и потом этот странный синтаксис. Erlang совершенно не похож на Java; нет ни методов, ни классов, ни объектов. И, обождите... знак равенства вовсе не означает «равно»... УДК 004.432.42Erlang ББК 32.973.28-018.1 Original English language edition published by No Starch Press, Inc. 38 Ringold Street, San Francisco, CA 94103. Copyright © 2013 by No Starch Press, Inc. Russian-language edition copyright © 2014 by DMK Press. All rights reserved. Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность технических ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим издательство не несет ответственности за возможные ошибки, связанные с использованием книги. ISBN 978-1-59327-435-1 (англ.) ISBN 978-5-97060-571-4 (рус.) © Fred Hebert, No Starch Press, Inc. © Оформление, перевод на русский язык, ДМК Пресс, 2019 Х35
Оглавление Об авторе 17 Предисловие от Джо Армстронга, одного из создателей языка 19 Предисловие 21 Благодарности 23 Вступление 25 Об этом уроке . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Что такое Erlang? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Что вам потребуется, чтобы начать . . . . . . . . . . . . . . . . . . . . . . . 29 Где получить помощь . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 1 Давайте начнём 33 Интерактивная консоль . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Ввод команд интерпретатора . . . . . . . . . . . . . . . . . . . . . . . 34 Выход из интерпретатора . . . . . . . . . . . . . . . . . . . . . . . . . 34 Некоторые основы Erlang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Числа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Неизменные переменные . . . . . . . . . . . . . . . . . . . . . . . . . 37 Атомы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Булева алгебра и сравнение . . . . . . . . . . . . . . . . . . . . . . . . 40 Кортежи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Списки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Генераторы списков . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Работа с двоичными данными . . . . . . . . . . . . . . . . . . . . . . 51 Двоичные строки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Двоичные генераторы . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 2 Модули 59 Что такое модули? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Объявление модуля . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Компилируем код . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Параметры компилятора . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 5
ОГЛАВЛЕНИЕ Макросы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Больше о модулях . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Метаданные . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Циклические зависимости . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3 Cинтаксис функций 71 Сопоставление с образцом . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Более сложные образцы . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Переменные в связке . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Охрана! Охрана! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Что за Если? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 В случае… если (case …of) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Что же лучше? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 4 Типы (вернее, их отсутствие) 85 Типизация сильная, как динамит . . . . . . . . . . . . . . . . . . . . . . . . 85 Преобразование типов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Охрана типов данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Для типозависимых . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 5 Привет, рекурсия 91 Длина списка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Длина хвостовой рекурсии . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Больше рекурсивных функций . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Функция дублирования duplicate . . . . . . . . . . . . . . . . . . . . . 96 Функция переворота reverse . . . . . . . . . . . . . . . . . . . . . . . 97 Функция отрезания sublist . . . . . . . . . . . . . . . . . . . . . . . . 98 Функция склеивания пар zip . . . . . . . . . . . . . . . . . . . . . . . 99 Быстро! Сортируй! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Думаем рекурсивно . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 6 Функции высшего порядка 109 Становимся функциональными . . . . . . . . . . . . . . . . . . . . . . . . . 109 Анонимные функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Больше анонимных функций . . . . . . . . . . . . . . . . . . . . . . . 112 Область видимости функции и замыкания . . . . . . . . . . . . . . . . . . . 113 Отображения, фильтры, свёртки и так далее . . . . . . . . . . . . . . . . . 115 Фильтры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Сворачиваемся (fold) . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Больше абстракций . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 6
ОГЛАВЛЕНИЕ 7 Ошибки и исключения 121 Коллекция ошибок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Ошибки компиляции . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Нет, ТВОЯ логика ошибочна! . . . . . . . . . . . . . . . . . . . . . . 124 Ошибки времени выполнения . . . . . . . . . . . . . . . . . . . . . . 124 Создание исключений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Исключения-ошибки error . . . . . . . . . . . . . . . . . . . . . . . . 128 Выходы процессов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 Броски исключений throw . . . . . . . . . . . . . . . . . . . . . . . . . 130 Обработка исключений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Обработка разных типов исключений . . . . . . . . . . . . . . . . . 132 После catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Попытка выполнить несколько выражений . . . . . . . . . . . . . . 135 Обождите, это ещё не всё! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Попробуйте try в дереве . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 8 Функциональный подход к решению проблем 143 Калькулятор в обратной польской записи . . . . . . . . . . . . . . . . . . . 143 Как работают RPN-калькуляторы . . . . . . . . . . . . . . . . . . . . 144 Создаём RPN-калькулятор . . . . . . . . . . . . . . . . . . . . . . . . . 145 Тестируем код . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Из Хитроу в Лондон . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 Рекурсивное решение проблемы . . . . . . . . . . . . . . . . . . . . 151 Пишем код (из Хитроу в Лондон) . . . . . . . . . . . . . . . . . . . . 153 Запуск программы без интерпретатора Erlang . . . . . . . . . . . . . . . . . 158 9 Короткий экскурс в структуры данных 161 Записи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Объявление записей . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Чтение значений из записей . . . . . . . . . . . . . . . . . . . . . . . 164 Совместное использование записей . . . . . . . . . . . . . . . . . . . 166 Хранилища данных ключ/значение . . . . . . . . . . . . . . . . . . . . . . . 167 Для небольших объёмов данных . . . . . . . . . . . . . . . . . . . . . 167 Большие хранилища: словари и общие сбалансированные деревья 169 Множество множеств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Упорядоченные множества ordsets . . . . . . . . . . . . . . . . . . . 172 Множества sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Общие сбалансированные множества gb_sets . . . . . . . . . . . . . 172 Множества множеств sofs . . . . . . . . . . . . . . . . . . . . . . . . . 172 Ориентированные графы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 Очереди . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 Конец недолгой прогулки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 7
ОГЛАВЛЕНИЕ 10 Автостопом по параллельным вычислениям 177 Не паникуйте . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Концепции конкурентности . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 Масштабируемость . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Устойчивость к сбоям . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Реализация конкурентности . . . . . . . . . . . . . . . . . . . . . . . 182 Не совсем непохоже на линейный рост . . . . . . . . . . . . . . . . . . . . . 183 Всего хорошего, и спасибо за рыбу! . . . . . . . . . . . . . . . . . . . . . . . 185 Порождение процессов . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Отправка сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 Получение сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . 189 11 Ещё о параллельной обработке 193 Утверждайте ваше состояние . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 Мы обожаем сообщения, но держим их в секрете . . . . . . . . . . . . . . . 195 Тайм-аут . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Избирательное получение . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Подводные камни выборочного приёма сообщений . . . . . . . . . 201 Больше подводных граблей . . . . . . . . . . . . . . . . . . . . . . . . 203 12 Ошибки и процессы 205 Связи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Это ловушка! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Старые исключения, новые идеи . . . . . . . . . . . . . . . . . . . . 209 Всё меняет exit/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Убивая меня (не очень) нежно... . . . . . . . . . . . . . . . . . . . . . 213 Мониторы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Именование процессов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 13 Проектирование параллельного приложения 221 Понимание проблемы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Определяем протокол . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 Построим фундамент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 Модуль событий . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 События и циклы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Добавляем интерфейс . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Сервер событий . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 Обработка сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Горячая любовь к коду . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Я сказал, спрячьте ваши сообщения . . . . . . . . . . . . . . . . . . . 240 Пробный запуск . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 Добавляем надзор . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 8
ОГЛАВЛЕНИЕ Пространства имён (вернее, их отсутствие) . . . . . . . . . . . . . . . . . . 245 14 Представляем OTP 247 Общий вид процесса, абстрактно . . . . . . . . . . . . . . . . . . . . . . . . 248 Простейший сервер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 Представляем сервер котят . . . . . . . . . . . . . . . . . . . . . . . . 249 Обобщаем вызовы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 Обобщаем внутренний цикл сервера . . . . . . . . . . . . . . . . . . 253 Функции для старта . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 Обобщаем сервер котят . . . . . . . . . . . . . . . . . . . . . . . . . . 255 Конкретная реализация против обобщения . . . . . . . . . . . . . . . . . . 257 Обратный вызов в будущее . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 Функция init . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 Функция handle_call . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Функция handle_cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Функция handle_info . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 Функция terminate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 .BEAM Me Up, Scotty! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 15 Ярость против конечных автоматов 267 Что такое конечный автомат? . . . . . . . . . . . . . . . . . . . . . . . . . . 267 Обобщённые конечные автоматы . . . . . . . . . . . . . . . . . . . . . . . . 271 Функция инициализации . . . . . . . . . . . . . . . . . . . . . . . . . 271 Функция ИмяСостояния . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 Функция handle_event . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 Функция handle_sync_event . . . . . . . . . . . . . . . . . . . . . . . . . 273 Функции code_change и terminate . . . . . . . . . . . . . . . . . . . . . . 274 Спецификация торговой системы . . . . . . . . . . . . . . . . . . . . . . . . 274 Покажи мне свои движения . . . . . . . . . . . . . . . . . . . . . . . 274 Определяем диаграммы состояний и переходы . . . . . . . . . . . . 276 Игровой обмен между двумя игроками . . . . . . . . . . . . . . . . . . . . . 283 Общедоступный интерфейс . . . . . . . . . . . . . . . . . . . . . . . 283 Функции общения между КА . . . . . . . . . . . . . . . . . . . . . . . 284 Функции обратного вызова gen_fsm . . . . . . . . . . . . . . . . . . . . . . . . 286 Это было что-то . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 Готовы к реальному миру? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 16 Обработчики событий 299 Справься-ка с этим! *перезаряжает ружьё* . . . . . . . . . . . . . . . . . . . . 299 Обобщённые обработчики событий . . . . . . . . . . . . . . . . . . . . . . . 300 Функции init и terminate . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Функция handle_event . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 9
ОГЛАВЛЕНИЕ Функция handle_call . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Функция handle_info . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Функция code_change . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Пришло время кёрлинга! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Табло со счётом . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 Игровые события . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Уведомите прессу! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 17 Кто присмотрит за наблюдателями? 315 Принципы работы наблюдателей . . . . . . . . . . . . . . . . . . . . . . . . 316 Использование наблюдателей . . . . . . . . . . . . . . . . . . . . . . . . . . 318 Стратегии перезапуска . . . . . . . . . . . . . . . . . . . . . . . . . . 319 Ограничения перезапуска . . . . . . . . . . . . . . . . . . . . . . . . 321 Спецификации на детей . . . . . . . . . . . . . . . . . . . . . . . . . . 321 Репетиция музыкальной группы . . . . . . . . . . . . . . . . . . . . . . . . . 324 Музыканты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 Наблюдатель за группой . . . . . . . . . . . . . . . . . . . . . . . . . 328 Динамические процессы-наблюдатели . . . . . . . . . . . . . . . . . . . . . 331 Динамическое использование стандартных наблюдателей . . . . . 331 Использование наблюдателя simple_one_for_one . . . . . . . . . . . . 333 18 Строим приложение 335 Пул процессов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 Теория луковых слоёв . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Дерево для пула . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 Реализация наблюдателей . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 Работаем с работниками . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 Пишем рабочий процесс . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 Беги, пул, беги . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Чистим бассейн . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 19 Строим приложение в стиле OTP 359 Пул — мой второй автомобиль . . . . . . . . . . . . . . . . . . . . . . . . . . 360 Файл ресурсов приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 Преображение пула . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 Поведение приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Из хаоса к приложению . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 Библиотечные приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 10
ОГЛАВЛЕНИЕ 20 Счетовод для приложений 373 От OTP-приложения к настоящему . . . . . . . . . . . . . . . . . . . . . . . 373 Файл приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 Модуль обратного вызова приложения и наблюдатель . . . . . . . . 376 Диспетчер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 Возврат результатов в стиле продолжений (CPS) . . . . . . . . . . . 378 Режимы диспетчера и приёма . . . . . . . . . . . . . . . . . . . . . . 381 Счётчик . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 Беги, программа, беги . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 Вложенные приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 Сложные завершения работы . . . . . . . . . . . . . . . . . . . . . . . . . . 393 21 Релиз — наше слово 395 Чиним текущие трубы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 Завершение работы виртуальной машины . . . . . . . . . . . . . . . 396 Обновление файлов приложения . . . . . . . . . . . . . . . . . . . . 396 Компилируем приложения . . . . . . . . . . . . . . . . . . . . . . . . 397 Релизы с помощью Systools . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 Создание загрузочного файла . . . . . . . . . . . . . . . . . . . . . . 399 Упаковка релиза . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 Релизы с помощью Reltool . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 Опции Reltool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 Рецепты для Reltool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 Отпустите меня, релизы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 22 Квест по прокачке процессов 417 Проблемы обновления приложений и релизов . . . . . . . . . . . . . . . . 417 Девятый круг Erl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 Process Quest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 Приложение regis-1.0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . 422 Приложение processquest-1.0.0 . . . . . . . . . . . . . . . . . . . . . . 423 Приложение sockserv-1.0.0 . . . . . . . . . . . . . . . . . . . . . . . . 424 Создаём релиз . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 Делаем Process Quest лучше . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 Обновляем функции code_change . . . . . . . . . . . . . . . . . . . . . 428 Файлы обновления приложений (appup) . . . . . . . . . . . . . . . 430 Обновляем релиз . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434 Обзор обновления релиза (relup) . . . . . . . . . . . . . . . . . . . . 438 11
ОГЛАВЛЕНИЕ 23 Ведро сокетов 441 Списки ввода-вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 UDP и TCP: бро-токолы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 UDP-сокеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 TCP-сокеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 Больше контроля с помощью inet . . . . . . . . . . . . . . . . . . . . . . . . 451 Возвращаемся к Sockserv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 Куда дальше? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 24 Совет Организации модульных наций 467 EUnit — а что такое EUnit? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 Генераторы тестов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 Заготовки окружения тестов . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 Больше контроля над тестами . . . . . . . . . . . . . . . . . . . . . . 477 Документация для тестов . . . . . . . . . . . . . . . . . . . . . . . . . 478 Тестируем приложение regis . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 Тот, кто вяжет EUnit’ы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 25 Медведи, ETS и корешки: noSQL-база данных в памяти забесплатно 491 Почему ETS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 Концепция в основе ETS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 Операции над ETS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 Создание и удаление таблиц . . . . . . . . . . . . . . . . . . . . . . . 496 Вставка и поиск данных . . . . . . . . . . . . . . . . . . . . . . . . . . 498 Встретить свою половинку . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500 Вас выбрали! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 DETS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 A Little Less Conversation, a Little More Action, Please . . . . . . . . . . . . . 508 Интерфейс . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 Подробности реализации . . . . . . . . . . . . . . . . . . . . . . . . . 510 26 Распреденомикон 515 Это моя громовая палка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 Заблуждения о распределённых вычислениях . . . . . . . . . . . . . . . . . 519 Сеть надёжна . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 Сетевые задержки незначительны . . . . . . . . . . . . . . . . . . . 520 Пропускная способность сети бесконечна . . . . . . . . . . . . . . . 521 Сеть хорошо защищена . . . . . . . . . . . . . . . . . . . . . . . . . . 522 Топология неизменна . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 Сеть администрирует один человек . . . . . . . . . . . . . . . . . . . 523 Передача данных бесплатна . . . . . . . . . . . . . . . . . . . . . . . 524 Сеть однородна . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525 12
ОГЛАВЛЕНИЕ В двух словах о заблуждениях . . . . . . . . . . . . . . . . . . . . . . . 526 Жив, или Живой мертвец . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 Моя вторая кепка — теорема CAP . . . . . . . . . . . . . . . . . . . . . . . . 528 Согласованность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 Доступность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 Устойчивость к разделению . . . . . . . . . . . . . . . . . . . . . . . 529 Выжившие среди зомби и CAP . . . . . . . . . . . . . . . . . . . . . . . . . . 530 Настройка Erlang-кластера . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 Сквозь пустыню на узле без имени . . . . . . . . . . . . . . . . . . . . 534 Соединение узлов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 Ещё инструменты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 Печеньки (куки) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 Консоль на удалённом узле . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 Скрытые узлы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 Стены сделаны из огня, а очки не работают . . . . . . . . . . . . . . . . . . 543 Зов из запределья . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544 Модуль net_kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544 Модуль global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544 Модуль rpc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 Закапывая распреденомикон . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 27 Распределённые приложения OTP 551 Добавляем больше к OTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 Аварийное переключение и возврат управления . . . . . . . . . . . . . . . 552 Волшебный восьмой шар . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 Строим приложение . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 Модуль наблюдателя . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 Модуль сервера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 Делаем приложение распределённым . . . . . . . . . . . . . . . . . 559 28 Common Test для необычных тестов 565 Что такое Common Test? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565 Структура Common Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 Создаём простую коллекцию тестов . . . . . . . . . . . . . . . . . . . . . . . 568 Выполняем тесты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569 Тестирование с состоянием . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 Группы тестов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574 Определение групп тестов . . . . . . . . . . . . . . . . . . . . . . . . 575 Свойства группы тестов . . . . . . . . . . . . . . . . . . . . . . . . . . 576 Комната совещаний . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577 Возвращение коллекций тестов . . . . . . . . . . . . . . . . . . . . . . . . . 582 Спецификации тестов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 13
ОГЛАВЛЕНИЕ Содержимое файла спецификации . . . . . . . . . . . . . . . . . . . 583 Создаём файл спецификации . . . . . . . . . . . . . . . . . . . . . . . 585 Запуск тестов с файлом спецификации . . . . . . . . . . . . . . . . . 585 Тестирование в больших масштабах . . . . . . . . . . . . . . . . . . . . . . . 586 Файл спецификации для распределённых тестов . . . . . . . . . . . 589 Запуск распределённых тестов . . . . . . . . . . . . . . . . . . . . . . 590 Интеграция EUnit внутри Common Test . . . . . . . . . . . . . . . . . . . . 591 Есть ещё? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592 29 Mnesia и искусство помнить 593 Что такое Mnesia? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594 Что хранит хранилище? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595 Данные для сохранения . . . . . . . . . . . . . . . . . . . . . . . . . . 595 Структура таблицы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 От записи к таблице . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598 О схемах и таблицах Mnesia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599 Создание таблиц . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601 Установка базы данных . . . . . . . . . . . . . . . . . . . . . . . . . . 602 Запуск нашего приложения . . . . . . . . . . . . . . . . . . . . . . . . 605 Доступ и контекст . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 Чтение, запись и даже больше . . . . . . . . . . . . . . . . . . . . . . . . . . 608 Реализуем первые запросы . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 Тест для добавления услуг . . . . . . . . . . . . . . . . . . . . . . . . . 610 Тесты для поиска в базе . . . . . . . . . . . . . . . . . . . . . . . . . . 613 Учётные записи и новые потребности . . . . . . . . . . . . . . . . . 617 Встреча с боссом . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619 Удаление записей, наглядно . . . . . . . . . . . . . . . . . . . . . . . . . . . 622 Запросы с генераторами списков . . . . . . . . . . . . . . . . . . . . . . . . 625 Помните Mnesia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 30 Спецификации типов и Dialyzer 629 PLT — это лучший бутерброд . . . . . . . . . . . . . . . . . . . . . . . . . . . 629 Успешная типизация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631 Выведение типов и несовпадения . . . . . . . . . . . . . . . . . . . . . . . . 634 Типа про типы типов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637 Одиночные типы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638 Объединённые и встроенные типы . . . . . . . . . . . . . . . . . . . 638 Определение новых типов . . . . . . . . . . . . . . . . . . . . . . . . 642 Типы в записях . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643 Типизируем функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644 Практикуемся в типизации . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649 Экспортирование типов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653 14
Типизированные поведения . . . . . . . . . . . . . . . . . . . . . . . . . . . 655 Полиморфические типы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657 Мы купили зоопарк . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 Некоторые опасности . . . . . . . . . . . . . . . . . . . . . . . . . . . 660 Ты — мой тип . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661 31 Карты 663 Об этой главе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663 EEP, EEP! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664 Какими будут карты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665 Модуль maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665 Синтаксис . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665 Неприукрашенные подробности . . . . . . . . . . . . . . . . . . . . 668 Коротенькие ножки для ранних релизов . . . . . . . . . . . . . . . . . . . . 669 Мексиканское противостояние . . . . . . . . . . . . . . . . . . . . . . . . . 670 Карты против записей против словарей . . . . . . . . . . . . . . . . 670 Карты против списков свойств . . . . . . . . . . . . . . . . . . . . . 674 Как бы я исправил эту книгу для добавления карт . . . . . . . . . . . . . . . 675 Вот и всё, ребята . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675 Послесловие 677 Другие применения Erlang . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 Библиотеки при участии сообщества . . . . . . . . . . . . . . . . . . . . . . 679 Ваши идеи меня заинтриговали... . . . . . . . . . . . . . . . . . . . . . . . . 680 Это конец? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 Приложение: синтаксис Erlang 681 Шаблон . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 Предложение на английском языке . . . . . . . . . . . . . . . . . . . . . . . 683 И, Или, Готово . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684 В качестве вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684 15
Об авторе Фред Хеберт (Fred Hébert) — программист-самоучка с опытом в разработке вебсайтов, веб-сервисов и общей разработки серверного программного обеспечения на различных языках. Его онлайн-учебник под названием «Изучай Erlang во имя добра!» («Learn You Some Erlang for Great Good!») считается одним из лучших способов изучить Erlang. Во время его работы в Erlang Solutions Ltd. он занимался созданием учебных материалов и преподавал курсы Erlang во многих странах Запада. В данный момент он работает над платформой ставок в реальном времени на показ рекламы с помощью Erlang (AdGear) и был признан Лучшим пользователем Erlang 2012 года (Erlang User of the Year). 17
Предисловие от Джо Армстронга, одного из создателей языка Учиться программированию — весело или, как минимум, должно быть весело. Если для вас это не весело, вам не понравится заниматься этим. Во время моей карьеры программиста я изучил несколько разных языков программирования, и это не всегда было весело. Является ли изучение нового языка весёлым, зависит в большой мере от того, как вам был представлен этот язык. Когда вы начинаете работать с новым языком программирования, поначалу кажется, что всё, что вы делаете, — это изучаете новый язык. Но если посмотреть глубже, вы занимаетесь кое-чем более основательным — вы изучаете новый способ мышления. Именно этот новый способ мышления и является восхитительным, а не те незначительные подробности пунктуации в языке или как он выглядит в сравнении с вашим любимым языком. Функциональное программирование — это одна из тех областей программирования, которые приобрели репутацию «сложных» (параллельные вычисления даже ещё сложнее), и таким образом написание книги об Erlang, которая бы освещала идеи функционального программирования плюс конкурентного программирования, — это проект, внушающий страх. Не ошибитесь здесь: введение в функциональное программирование не очень лёгкое, и введение в конкурентное программирование тоже имеет свои сложности. Чтобы сделать и то, и другое с юмором и лёгкостью, надо иметь особенный талант. Фред Хеберт показал, что у него имеется как раз такой талант. Он объясняет сложные идеи так, что они выглядят простыми. Одним из величайших препятствий на пути изучения Erlang является не столько то, что идеям его свойственна сложность, но и то, что они сильно отличаются от идей большинства других языков, которые вам встречались. Для изучения Erlang вам следует на время забыть то, что вы изучили в других языках. Переменные в Erlang не переменны. Вам не следует программировать в ожидании ошибки. Процессы действительно очень дёшевы, и вы можете иметь тысячи их одновременно, даже миллионы, если вам так захочется. Ох, и потом этот странный синтаксис. Erlang совершенно не похож на Java; нет ни методов, ни классов, ни объектов. И, обождите... знак равенства вовсе не означает «равно», вместо этого он означает «сопоставь с этим образцом». Фред вовсе не устрашается этих проблем; он работает над темой с деликатным сухим юмором и объясняет сложные темы так просто, что мы забываем о сложности. 19
ПРЕДИСЛОВИЕ ОТ ДЖО АРМСТРОНГА Это четвёртая большая книга об Erlang, и она является прекрасным дополнением к библиотеке Erlang. Но она не только про Erlang. Многие из идей в книге Фреда одинаково хорошо подходят и к Haskell, и к OCaml или F#. Я надеюсь, что многие из вас получат удовольствие, читая книгу Фреда, так же как и я, и что вы сочтёте изучение Erlang процессом приятным и наводящим на мысли. Если вы будете вводить программы, написанные в этой книге, и запускать их по мере чтения, вы узнаете ещё больше. Написание программ намного сложнее, чем их чтение, и первым шагом будет дать вашим пальцам привыкнуть к набору программ и избавиться от мелких ошибок синтаксиса, которые неизбежно происходят. По мере углубления в книгу вы будете писать программы, которые довольно сложно написать на других языках, но надеюсь, что вы не заметите этой сложности в Erlang. Вскоре вы будете писать распределённые программы. А потом становится весело... Спасибо, Фред, за прекрасную книгу. Джо Армстронг (Joe Armstrong) Стокгольм, Швеция 6 ноября, 2012 г. 20
Предисловие Эта книга изначально была написана в виде веб-сайта, который до сих пор доступен по адресу http://learnyousomeerlang.com/ (спасибо отзывчивости издательства No Starch Press в отношении всех вещей, касающихся публикации и технических материалов). Поскольку первые главы увидели свет ещё в 2009 году, книга «Изучай Erlang» вырос ла из небольшого урока на три главы в одну из книг, рекомендованных официальной документацией по изучению Erlang, и стала большим достижением в моей жизни. Я озадачен этим и благодарен за всё, что это мне принесло, начиная от друзей и заканчивая работой и титулом Лучший пользователь Erlang 2012 года. Когда я начал написание этой книги, одной из моих целей стало сделать её как можно более доступной для как можно большего количества разработчиков. Вот почему английская версия появилась в виде бесплатного веб-сайта, и продолжает оставаться бесплатной по сей день. Одна проблема, которую я не смог решить, это языковой барьер: книга была написана на английском и это сильно ограничило аудиторию её читателей. Русскоязычное сообщество Erlang пыталось перевести книгу множество раз, часто даже во время её написания и размещения на сайте. Несмотря на эти усилия, ни одна из этих инициатив не принесла плодов. Дмитрий Литовченко нашёл меня в IRC-чате и спросил разрешения выполнить перевод. То, что вы держите сейчас в руках, является результатом его усилий и настойчи вости вместе с поддержкой, которую предоставила команда издательства ДМК Пресс. Большое им спасибо и, надеюсь, вам понравится результат их работы. Новичку Когда вы смотрите на Erlang-программистов издалека, как посторонний, они могут показаться странным небольшим сообществом людей, которые верят в принципы, которым больше никто не должен или не хочет следовать. Их принципы выглядят непрактичными, ограниченными в том, как их можно применить. Хуже того, граждане страны Erlang могут выглядеть подобно членам религиозной секты, абсолютно уверенным в том, что им известен один истинный путь к сердцу программного обеспечения. Это тот же «один истинный путь», который недавно проповедовали фанатики языков программирования из семейств Lisp и Haskell, гордые ученики школы мышления в стиле формальных доказательств, программисты на Smalltalk, поклонники стеков из мира Forth и так далее. Всё так же, всё те же; они обещают огромный успех и доставляют обещанное разными способами, но программы, которые 21
Доступ онлайн
В корзину