Эволюция структур данных в языках программирования

Сон сетки об эволюции

Сон сетки об эволюции

Есть в природе одна универсальная последовательность, которая сопровождает любые эволюционные процессы. Она получила название «фазовый закон» и её проще всего проиллюстрировать тем, как мы погружаемся в изучение любого нового предмета.

Первоначально нам необходимо познакомиться с предметной областью, узнать, из чего она состоит. Так в мастерской мы учимся различать конкретные инструменты, материалы, изделия друг от друга. Нам пока непонятно до конца их назначение, мы их ещё в руках не держали, но если мы не научимся их различать, то не поймём и дальнейшей премудрости. Аналогично, в разработке программного обеспечения мы знакомимся с понятиями переменной, массива, цикла, ссылки, составных типов данных. Учимся различать данные, переменные, константы и определения.

После того, как мы перестали всё это путать между собой и выучили, как оно называется, мы получаем возможность изучать, что с этими сущностями вообще можно делать. Как сработать табуретку, или телеграм-бота. Для этого нам необходимо узнать правила их использования, а правила эти основаны на обобщениях, т.е., классификациях. «Все переменные определяем в начале функции», «Вместо goto нужно применять циклы в их ассортименте», «гвозди забивай, шурупы закручивай» и т.п. Эта способность к классификации возникает только после того, как у нас появится что классифицировать, т.е., когда мы уже пройдём первую фазу будем знать, что существуют var, array, goto, for, while… Таким образом, классификация становится возможна не ранее второй фазы.

После того, как мы поняли из чего мир устроен и где снег башка попадёт, мы будем допущены к практической работе. Допускать нас до неё раньше — отправлять на верную погибель, потому что без знания правил математическое ожидание результата нашей деятельности будет сильно меньше половины: рано или поздно мы либо молотком по пальцам попадём, либо обесточим чьё-нибудь жизнеобеспечение, либо базу данных удалим… Поэтому практика идёт третьей по очереди и в ней мы оттачиваем мастерство.

Мастерство позволяет нам принести плоды окружающим. И за это окружающие начинают нас ценить и предпринимать усилия к тому, чтобы мы никуда от них не ушли. Среда сама подтаскивает к нам такие ресурсы, на которые мы сами, даже будучи профессионалами, не могли бы надеяться. Так начинается управление — четвёртая и последняя фаза освоения профессии. В этот момент клиенты начинают возвращаться и приводить новых, а если мы трудимся как работники, то можем торговаться за зарплату, за привилегии, выбивать себе удалёнку, или, наоборот, кабинет с хорошим видом, влиять на набор новых сотрудников и т.п. Но дополнительный приток ресурсов — это лишь новая возможность, которая, требует умения грамотно и своевременно ими распоряжаться. Без этого умения достигший успеха человек становится слишком лакомым куском и лёгкой мишенью для более социально продвинутых товарищей.

Хотя описанная последовательность, на первый взгляд, может показаться эмпирикой, это не так. Дело в том, что у описанных выше четырёх видов деятельности есть формальное различие — количество параметров, необходимых для производства операций в рамках данной фазы, возможность эффективно задействовать которое обеспечивается бэкграундом пройденных фаз.

Так для различения нам достаточно операций с одним операндом: мы просто производим сравнение с шаблоном.

Для классификации нам необходимо два операнда: шаблон и название класса.

Для дела нам необходимо уже три операнда: добавляется продукт, который передаётся из одного места в другое.

А для управления не обойтись без четырёх: управление — это когда продукт передаётся не в результате непосредственного усилия, а в результате коммуникации с тем, кто приложит усилие.

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

Нарушение порядка фаз возможно — при вмешательстве внешних сил, но естественный переход к следующей фазе после такого нарушения, без добора пропущенного бэкграунда будет очень энергозатратным.

В используемой парадигме параметр, по которому различаются как фазы, так и эволюционные циклы, называется «сложность». Чем выше сложность отношений, тем выше доступная длина цепочек передела. При этом низкая сложность не препятствует созданию крупных форм: так пирамиды и готические соборы были созданы за счёт искусной реализации достаточно простых технических возможностей в достаточно коротких производственных цепочках. Но сегодняшняя атомная станция уже требует очень длинных цепочек, которые в древние времена были как невозможны организационно, так и не эффективны экономически. Зато сегодня снижены требования к искусности: координация невозможна без унификации, а унификация существенно снижает требования к мастерству конечных исполнителей.

Старички ещё помнят Volkov Commander — панельный файловый менеджер, написанный целиком на ассемблере, чтобы получить компактность и скорость. Сегодня, за счёт унификации интерфейсных узлов, создание подобных систем стало делом практически бытовым, а объём доступного вычислительного ресурса в текущей фазе позволяет не замечать избыточного размера приложения.

На приведённом рисунке изображена общая схема описываемого процесса. Усложнение в этой схеме производится в порядке номеров, а соединение при переходе на 4+1 уровень происходит по кругу.

Фазовый закон схематично

Фазовый закон схематично

В скобках отмечу, что понимание этой последовательности окажется весьма полезным для тех кто начинает учить чему-то других. Есть люди, которые интуитивно чувствуют описанный выше порядок раскрытия знания, а те, кто не чувствует, зачастую бывает склонен начинать изложение материала задом наперёд и это оборачивается большой потерей времени и нервов и для учеников и для учителя. Итак: вначале всё называем и только потом рассказываем, что с этим делать. Не наоборот и не одновременно.

Структуры данных в языках программирования

Поскольку эта нарастающая последовательность достаточно очевидна, не стоит удивляться, что технический прогресс развивается по тому же лекалу. Неудивительно, что человечество, впервые столкнувшись с понятием программирования прошло ровно этот же путь.

Если мы будем рассматривать эволюцию структур данных в языках программирования, то увидим, что у нас все начинается с понятия именованной переменной. Для обращения к именованной переменной нам нужно знать всего один адрес памяти. При помощи переменной, которая не предполагает ещё ни массивов, ни перечислений мы можем строить только конечные автоматы.

Конечный автомат на определённом количестве именованных переменных — это, по сути, объект. Но для нас то, что он «объект» пока не играет никакой роли, потому что мы пока не умеем их перечислять. Т.е., чтобы создать второй объект, нам нужно создать полностью новый, отдельный, хотя и идентичный первому набор переменных. Примерно так:

chair_x = 1
chair_y = 1
table_x = 2
table_y = 1

Во второй фазе у нас должна появиться способность к классификации. Эту роль выполняют массивы. Появляются множества элементов, и нам, чтобы адресоваться к ним, необходимо уже 2 параметра: имя массива и индекс (или, ближе к «железу»: адрес начала массива и смещение).

В третьей фазе мы осваиваем взаимодействие. Взаимодействие требует методов, поэтому у нас появляются объекты — это когда мы, по сути, делаем не массивы переменных, а массивы конечных автоматов и методы являются «рычагами» этих автоматов. Здесь нам необходимо уже три параметра: два для адресации в массиве и один для адресации свойства объекта.

Примечательно, что хотя мы имели возможность косвенно (по ссылке) обращаться к ячейкам памяти и функциям даже на уровне конечных автоматов (что выразилось в создании языка LISP), и в процедурных C и Pascal, реальный расцвет этого метода приходится именно на третью фазу, когда вводится «сахар» объектного полиморфизма. Именно в третьей фазе косвенная адресация функций в обёртке динамических методов становится ширпотребом, а не доблестью квадратноголовиков.

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

В четвёртой фазе мы должны получить способность решать задачи управления. Поэтому мы, добросовестно пройдя все три предыдущих этапа, обнаруживаем нейросети, а точнее — слой нейросети, состоящий из массивов однотипных конечных автоматов (объектов) — нейронов.

Эти слои выстраиваются в последовательности. Такая последовательность слоёв уже не кодирует какую-то конкретную логическую операцию, а служит полем для отражения любых причинно-следственных операций. По сути, глубокая нейросеть, со всеми её коэффициентами — это матрица причинно-следственных связей определённой среды и реализует возможность сопоставлять такие операции между собой. Четвёртым параметром, таким образом, становится номер слоя и это ещё один элемент усложнения.

Возникает закономерный вопрос:, а что же у нас будет дальше?

Четвёртая фаза является последней фазой эволюционного генезиса и дальше деятельность превращается во что-то, на порядок более сложное. Для этого все 4 освоенных вида деятельности, прежде разделённые во времени, как последовательные фазы, начинают проявлять себя одновременно, используя для этого разделение в пространстве. Это как автомобиль, который на заводе собирали по частям, а на дороге у него одновременно двигатель двигает, колёса крутятся, салон перевозит, а кузов удерживает все их вместе. Именно ради этой одновременности его и собирали.

Это называется «хозяйственный цикл»: различение начинает использоваться для поиска ресурсов, ресурсы сразу передаются в работу, товар реализуется, выручка и остатки анализируются и инвестируются в поиск новых ресурсов.

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

Оглядываясь назад, мы видим, что с увеличением сложности количество языков программирования постоянно росло. Огромное количество сегодняшних библиотек и фреймворков — это, по сути, развитые предметные языки. То количество нейросетей, которые предстоит открыть и принять на вооружение ожидается ещё большим, чем число языков программирования. Причём трудоёмкость подготовки данных и их параметризации не должна нас пугать — уже сегодня для этого широко применяют сами трансформерные нейросети. В частности, именно этому подходу мы обязаны появлением русской локализации Llama-2 «Saiga».

Но нейросети — это уже понятно. Рабочая лошадь, на которую мы скоро перестанем обращать внимание так же, как перестали обращать внимание сперва на сотовые телефоны, а затем и на смартфоны. И, хотя это — тоже целый интересный мир, который найдёт своего массового разработчика, подлинный интерес сегодня представляет сущность нового явления, первой ласточкой которого является трансформер с механизмом внимания.

По сути, у нас появляется технический объект нового типа, в котором объединены механизмы всех четырёх предыдущих фаз развития информационно-технических объектов.

Мы его определяем как «процесс», т.е., по своему уникальное «живое» явление с жизненным циклом. При всей фантастичности, это достаточно простое умозаключение: ведь если у нас есть нечто, способное отражать отрезок времени, как целое, т.е. жизненный цикл, то оно само обязано быть, как минимум, отрезком времени с жизненным циклом. А отрезок времени, имеющий жизненный цикл называется «процесс».

О природе и анатомии процессов необходимо говорить отдельно. Но если вкратце, проводя аналогию с чем-то известным, то можно сказать, что процесс — это волновая часть корпускулярно-волнового континуума, а новый элемент автоматизации (хотя уже — не автоматизации, для этого ещё нет названия) объединит в себе свойства частицы и волны — объекта и процесса.

Когда логика машины сможет вот это переваривать, на что это будет похоже?

Мы можем сказать, что если раньше на каждом из этих уровней вычисления мы считали «бобы в корзиночке», то после того, как эти уровни объединяются, становятся единым процессом, т. е. «живой» системой, то нам теперь придётся считать «улиток».

Улиток, конечно, тоже можно пересчитать, но они при этом все немного разные, они друг друга толкают, расползаются, им что-то нравится или не нравится, с ним что-то происходит. И вот это «что-то» требует совершенно другого подхода к прогнозированию. Потребуется создание нового исчисления, которое будет работать уже не с численными, а с качественными (и, не побоюсь этого слова — смысловыми) единицами. Как это возможно? А присмотритесь к схеме в этой статье: вроде бы мы пронумеровали фазы строгим порядком, но эти номера отражают не количества, а качество, не объём, а смысл происходящего.

© Habrahabr.ru