УДК 004.432.42Erlang
ББК 32.973.28-018.1
Х35
Хеберт, Фред.
Изучай Erlang во имя добра! / Пер. с англ. Литовченко Д. — М.: ДМК Пресс, 2019. —
688 с.: ил.
ISBN 978-5-97060-571-4
Усеянная беспечными иллюстрациями и смесью развлекательных и практических
примеров программ, книга «Изучай Erlang во имя добра!» является отличным пунктом
отправления в иногда безумный, но всегда восхитительный мир Erlang.
Вероятно, вас привело к Erlang обещание конкурентности или параллелизма.
Возможно, это аспект языка, касающийся распределённых вычислений, а может быть,
необычный подход к устойчивости против сбоев.
Одним из величайших препятствий на пути изучения Erlang является не столько
то, что идеям его свойственна сложность, но и то, что они сильно отличаются от
идей большинства других языков, которые вам встречались. Переменные в Erlang
не переменны. Вам не следует программировать в ожидании ошибки. Процессы
действительно очень дёшевы, и вы можете иметь тысячи их одновременно, даже
миллионы, если вам так захочется. Ох, и потом этот странный синтаксис. Erlang
совершенно не похож на Java; нет ни методов, ни классов, ни объектов. И, обождите...
знак равенства вовсе не означает «равно»...
Издание предназначено как для начинающих изучать Erlang, так и для более
опытных разработчиков. Даже в том случае, если читатель очень хорошо знаком с
Erlang, книга сможет стать справочником и даже научить чему-то новому.
УДК 004.432.42Erlang
ББК 32.973.28-018.1
Original English language edition published by No Starch Press, Inc. 38 Ringold Street,
San Francisco,CA94103. Copyright©2013 byNoStarch 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
Стр.5
Оглавление
Об авторе
Предисловие от Джо Армстронга, одного из создателей языка
Предисловие
Благодарности
Вступление
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
Стр.6
ОГЛАВЛЕНИЕ
Макросы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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
ОГЛАВЛЕНИЕ
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
Стр.8
ОГЛАВЛЕНИЕ
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
Стр.9
ОГЛАВЛЕНИЕ
14 Представляем OTP
Пространства имён (вернее, их отсутствие) . . . . . . . . . . . . . . . . . . 245
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
Стр.10
ОГЛАВЛЕНИЕ
Функция 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
Стр.11
ОГЛАВЛЕНИЕ
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
Стр.12
ОГЛАВЛЕНИЕ
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
Стр.13
ОГЛАВЛЕНИЕ
В двух словах о заблуждениях . . . . . . . . . . . . . . . . . . . . . . . 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
Стр.14
ОГЛАВЛЕНИЕ
Содержимое файла спецификации . . . . . . . . . . . . . . . . . . . 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
Стр.15
Типизированные поведения . . . . . . . . . . . . . . . . . . . . . . . . . . . 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
Стр.16