Начиная с этой статьи мы приступаем к публикации концепта реализации нового языка программирования Hi.

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

Мы предполагаем, что для понимания изложенного материала читателю знакомы синтаксис и семантика нескольких распространенных языков программирования общего назначения.

Don't bite my finger, look where I am pointing
Warren S. McCulloch, 1960s

Исходная постановка задачи


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

В целом, при некоторых ограничениях, эта задача была решена еще в 2018 году приложением Helius' — full of life, которое можно найти в App Store.

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

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

Так как хорошо спроектированной интеллектуальной системе одинаково «удобно» сгенерировать синтаксис любого непротиворечивого языка в любой форме, то для того, чтобы использовать язык коммуникаций между «искусственным» и «естественным» интеллектом логично использовать традиционный алгоритмический код, сделав его максимально удобным для паттернов мышления человека, знакомого с мейнстримовыми языками, предком которых был Algol. Это потомки по линии Pascal (Ada, Modula) и C (C++, Java, Swift). Впрочем, наш концепт построения абстракций и внимательное отношение к скобкам близки к духу Scheme (Lisp), а интеграция команд программного окружения в выразительные средства языка соответствует идеям скриптовых языков, винтажному BASIC для первых микрокомпьютеров и проекту Oberon – системы Никлауса Вирта.

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

В итоге сформулируем назначение языка как обмен алгоритмами между искусственным и естественным интеллектом, совместное программирование задач (игр и головоломок) для себя и других, свободный обмен текстами программ.

Hi World


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

PRINT “Hello world!”

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

Представим два более интересных примера: нахождение для двух целых чисел наибольшего общего делителя в императивном стиле и с использованием рекурсии:

FUN gcd
   INPUT a: INT
   INPUT b: INT
   WHILE a ~= b LOOP
      IF a > b THEN a -= b ELSE b -= a ENDIF
   REPEAT
   PRINT “gcd = “, a
RETURN

FUN gcd _ a: INT, _ b: INT -> INT
   IF b == 0 THEN RETURN a ENDIF
RETURN gcd b, (a % b)

PRINT gcd 6, 9 
# печатает 3

Требования для языка Hi


Каждый удачный язык проектируется с конкретным назначением, которое определяет его синтаксические особенности и семантику. Например, ASSEMBLER был предназначен для прямого кодирования команд процессора в мнемонической форме, удобной человеку; BASIC (тот который с номерами строк и оператором GOTO) — удачно продолжил идею прямой трансляции команд высокоуровневому интерпретатору. Hi programming language предназначен стать языком команд и алгоритмов для коммуникаций между Human и абстрактным интеллектом некоторой спроектированной системы.

Как логичное следствие, программным кодом считается не скомпилированный машинный код и не байт-код виртуальной машины, а исходный текст (листинг), включая комментарии. Соответственно, внутренняя реализация кода никоим образом не стандартизируется и оставляется на усмотрение реализации интерпретаторов или компиляторов.

Итак, наша главная цель – обмен мыслями при помощи формального языка. Введем три основных требования:

  1. Язык должен быть легким в освоении человеком
  2. Язык должен быть надежным в использовании
  3. Язык должен быть способен к организации очень сложных программных систем.

Давайте подробнее исследуем эти базовые требования.

Язык должен быть легким в освоении


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

Следовательно, мы используем конструкции вида LOOP…REPEAT, а не {…}. Фигурные скобки в качестве приятного бонуса будем использовать вот так:
s = {1, 2, 3} у нас будет обозначать присвоение переменной s множества из трех целых чисел.
a = [1, 2, 3] у нас будет обозначать присвоение переменной a массива из трех целых чисел.

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

2) Для арифметических выражений используем запись вида: a + b + c, а не (+ a b c), как в семействе LISP.

3) Природа нашего скриптового языка требует встроенной библиотеки всех необходимых функций в окружение языка без необходимости подключения внешних фреймворков.

4) Используем нативную алгоритмизацию паттернов мышления: императивный язык с возможностью рекурсивных функций и элементами функциональных вычислений. Как мы в дальнейшем рассмотрим на одном из примеров, императивный стиль вполне удобен и для программирования приложений, основанных на архитектуре обработки событий в декларативном ключе, подобных SwiftUI. Иначе говоря, термины «императивный» и «декларативный» скорее отображают позицию наблюдателя, чем реальность, данную нам в ощущение.

5) Следим за отсутствием избыточности синтаксических конструкций и эргономичностью ввода символов кода. Мы используем новую строку в качестве разделителя. Впрочем, как и в языке Swift, можно использовать «;» в одной строке в качестве разделителя для нескольких выражений. При этом наше инженерное образование категорически протестует против придания синтаксической значимости отступам в тексте программы, как это ранее использовалось в Fortran, а в настоящее время в Python.

Надежный язык


Необходимым условием существования сложных систем во времени является требование полной семантической однозначности и исполнимости каждой корректно написанной программы без исправлений при неизбежной эволюции и усложнении языка в будущем. Как решить эту проблему надежности работы программ при его неизбежном развитии и расширении? Для того, чтобы избежать конфликта совпадения идентификаторов и зарезервированных слов мы используем простой и эффективный способ, как сделано, например, в Oberon. Язык HI резервирует все идентификаторы с буквами в верхнем регистре без цифр с количеством символов более одного как служебные. Таким образом допустимыми идентификаторами, написанными вручную программистом или сгенерированными интеллектуальной системой, являются следующие примеры:

foo, Foo, f_001, F1, F, for

Примеры идентификаторов, которые зарезервированы языком:

FOO, FOR, HI, YES, EVERYRESTRICTIONMATTER

В целях надежности кода мы используем статическую типизацию с возможностью автоматического вывода типов из деклараций вида:

LET x = 6  # константа x имеет тип INT
VAR boolean = TRUE  # объявление переменной boolean типа BOOL

Мы различаем константы и переменные не для оптимизации времени исполнения кода, а для того, чтобы разработчик хорошо понимал предназначение тех объектов, которыми он управляет.

Язык для построения очень сложных программных систем


Архитектура любого универсального языка должна предусматривать продуманную возможность построения сложных программ из небольших автономных кусочков, допустим до 250 LOC в одном источнике, ибо, да простит нас уважаемый Читатель, только сканеру и парсеру легко работать с исходными текстами любой сложности, а человеку даже перемножить пару трехзначных целых чисел тяжело без калькулятора.

Мы пока оставим в стороне реализацию архитектуры сложных систем на языке Hi и детально разберем эти вопросы в последующем при изложении концепции организации классов – протоколов, коммуникации между ними и способам построения их иерархии. Заметим только, что архитектура сложных приложений будет строиться из небольших автономных, легко читаемых и модифицируемых фрагментов и вдохновение здесь мы черпали не в изучении computer science, а в архитектуре взаимодействия клеток и органов живых организмов. Тело обыкновенного человека составляет порядка 50 триллионов жизнеспособных клеток, успешно функционирующих несмотря на сложные окружающие условия, наличие множества паразитов и постоянные повреждения миллионов микрокомпонентов. Создателю компьютерной системы, которая полностью прекращает свое функционирование вследствие единственного обращения к несуществующему индексу массива здесь есть чему поучиться.

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

Ограничения


На практике всегда, когда мы применяем какие – либо требования для конструирования систем, то чем-то приходится или жертвовать или на что-то не обращать внимания. Для нас в конструкции языка Hi не имеет принципиального значения:

  • Точная совместимость синтаксиса с другими языками программирования
  • Возможность использования существующих внешних библиотек кода или интеграция с другими программными системами
  • Оптимизация скорости исполнения программ c ориентацией на аппаратные возможности и n-битную архитектуру компьютеров
  • Сложность реализации интерпретаторов / компиляторов для полной версии языка
  • Так как исполняемый интерпретатором программный код — это исходный текст, то не предусмотрено встроенной защиты от копирования и легкой модификации в случае наличия доступа к источнику

В завершение скажем о происхождения приветливого наименования языка программирования HI, Hi или hi. Допустим это будет Helius’ interactive Programming Language или Human Intelligence Programming Language. В отличие от всех конструкций нашего языка это единственный мета — идентификатор, который не имеет однозначной семантики.

В следующей статье представим описание Hi Basic Programming Language «на одной» странице и затем разберем логику конструирования синтаксиса, следуя требованиям тезисов, представленных выше.