Раздел 21 · Haskell

Списки и рекурсия

junior~55 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Списки и рекурсия

Список это главный носитель данных начального Haskell, а рекурсия заменяет циклы. В этом уроке: устройство списка из cons-ячеек, иммутабельность и разделение хвостов, паттерн-матчинг и guards, рекурсия по форме данных, аккумуляторы и хвостовая рекурсия, и почему String это просто [Char] со всеми последствиями.

Идея

Плохая новость: в Haskell нет цикла for. И while нет. И не будет.

Это не упрямство дизайнеров языка, а прямое следствие урока 01: цикл живёт на мутации. i++, аккумулятор-переменная, флажок выхода, всё это перезапись значений, которой в чистом языке не существует. Хорошая новость: всё, что ты делал циклом, делается рекурсией, и большую часть этой рекурсии ты даже не будешь писать руками. В уроке 04 появятся map, filter и компания, которые заберут себе девять циклов из десяти. Но они сами написаны через рекурсию, и сегодня мы спускаемся на этот нижний этаж: после него стандартная библиотека перестанет быть магией.

Опорная мысль урока такая: форма функции повторяет форму данных. Посмотри, как устроен список. Это не массив, под ним нет непрерывного куска памяти. Список в Haskell определяется рекурсивно: он либо пуст, либо это один элемент плюс ещё один список. Всё:

[1, 2, 3]  это сахар для  1 : (2 : (3 : []))

┌───┬───┐    ┌───┬───┐    ┌───┬───┐
│ 1 │ ●─┼───▶│ 2 │ ●─┼───▶│ 3 │ ●─┼───▶ []
└───┴───┘    └───┴───┘    └───┴───┘

Двоеточие называется cons: оно приклеивает элемент слева к существующему списку. Раз структура данных собрана из двух случаев (пустой список и cons), то и функция над ней распадается на два случая: что делать с пустым и что делать с головой и хвостом. Это не приём и не паттерн, это геометрия: рекурсивные данные порождают рекурсивные функции, и форма кода буквально срисовывается с формы данных.

И одно знакомое слово напоследок. Cons-ячейки иммутабельны, поэтому хвост можно разделять между списками: 1 : xs не копирует xs, а ссылается на него. Это тот самый structural sharing из урока про персистентные структуры, только здесь он не библиотека, а способ существования каждого списка в языке.

премиум-урок

Продолжение в премиуме: 1 200 ₽ в месяц или 10 000 ₽ в год. Вместе с ним серверные проверки задач и школьные токены AI-коуча.

Оплата пока не подключена: премиум и курсы открываются промокодом.