До сих пор мы едва коснулись синтаксиса Hyperlambda. Чтобы понять синтаксис, вам нужно понять взаимосвязь между Hyperlambda и лямбда-объектами, где лямбда-объекты для Hyperlambda эквивалентны тому, что DOM является для HTML. Чтобы снова понять лямбда-объекты, полезно представить себе некоторый традиционный псевдокод C#/Java.

class Node
{
   string Name;
   object Value;
   List<Node> Children;
}

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

Когда вы пишете Hyperlambda, вы буквально динамически объявляете объект, каким-то образом напоминающий вышеуказанный тип. Рассмотрим пример цикла [while], с которого мы начали пару статей назад.

.no:int:0
while
   lt
      get-value:x:@.no
      .:int:20
   .lambda
      log.info:Howdy from while
      math.increment:x:@.no

Приведенный выше лямбда-объект имеет один неявный корень Node, который также имеет двух дочерних элементов с именами [.no] и [while]. Наш узел while снова имеет еще двух дочерних элементов с именами [lt] и [.lambda] и так далее. Двоеточие : отделяет имя узла от его значения, а 3 пробела открывают дочернюю коллекцию, позволяя вам объявить дочерние узлы узла выше.

Кровавые подробности

Синтаксический анализатор Hyperlambda снова просто анализирует Hyperlambda как структурированный текст и динамически создает структуру Node с учетом указанной Hyperlambda в соответствии с приведенным выше набором правил. Затем, когда синтаксический анализатор Hyperlambda построил лямбда-объект, он передает этот лямбда-объект в качестве единственного аргумента в слот [eval] (вспомните здесь 'function'). Слот [eval] снова подчиняется чрезвычайно простому рекурсивному набору правил, который выглядит следующим образом.

void eval(Node node)
{
   foreach(var idx in node.Children)
   {
      if (!idx.Name.StartsWith("."))
         signal(idx.Name, idx);
   }
}

Вышеизложенное является некоторым упрощением, но на самом деле это весь «язык программирования» в сжатом виде. Приведенный выше метод signal снова просто вызывает метод интерфейса в классе, где тип берется из строки ==> type Dictionary, и создает экземпляр типа с использованием внутреннего контейнера IoC, позволяя вам объявлять типы на языке программирования хоста, который создаются с использованием внедрения зависимостей.

Если у вас сейчас немного болит голова, просто игнорируйте последние два абзаца, они в основном предназначены для объяснения тем, кто ищет более кровавые подробности. Однако помните, что Hyperlambda — это самый простой и легкий для реализации язык программирования на планете, хотя бы по той причине, что во время «выполнения» не происходит ни компиляции, ни интерпретации, а только простая операция синтаксического анализа, создание графического объекта, который затем снова рекурсивно выполняется как «дерево выполнения». Таким образом, лямбда-объект для Magic — это то же самое, что машинный код для вашего процессора.

Это приводит к среде песочницы, где выполнение происходит виртуализировано через язык программирования хоста, предоставляя слоты как услугу, аналогично тому, как виртуализация происходит в других местах в вычислительной технике. Если гипервизор — это виртуальный ЦП или операционная система, то Hyperlambda — это «гипер-исполнитель», где базовая логика реализована на основном языке программирования, которым для Magic является C#, а Среда выполнения .Net 6. Однако вам никогда не придется каким-либо образом возиться с базовым языком программирования хоста, C# или .Net. И вы, вероятно, могли бы создать среду выполнения Hyperlambda на Java, PHP или C++, если бы захотели.

Система типизации Hyperlambda

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

.no:int:0

Вышеприведенное объявляет узел с именем [.no], его значением 0 и объявлением его типа int, подразумевая тип int из .Net 6. В Hyperlambda есть целый ряд типов, и вы можете увидеть большинство из них ниже и то, как они сопоставляются с типами пространства имен .Net 6 System.

  • строка = System.String
  • короткий = System.Int16
  • ushort = System.UInt16
  • целое = System.Int32
  • uint = System.UInt32
  • длинный = System.Int64
  • ulong = System.UInt64
  • десятичный = System.Decimal
  • двойной = System.Double
  • одиночный = System.Float
  • float = System.Float — Псевдоним для вышеуказанного
  • bool = System.Boolean
  • дата = System.DateTime
  • время = System.TimeSpan
  • guid = System.Guid
  • char = System.Char
  • байт = System.Byte
  • x = magic.node.extensions.Expression
  • узел = magic.node.Node

Это позволяет вам, например, объявлять логические значения, как показано ниже.

.source:bool:true
.result
if
   get-value:x:@.source
   .lambda
      set-value:x:@.result
         .:yup!
else
   set-value:x:@.result
      .:nope!

Выше приведен простой оператор if/else, устанавливающий значение узла [.result] в соответствии со значением узла [.source]. Если вы выполните его в оценщике Magic, вы увидите что-то вроде следующего.

Лямбда-выражения

Последняя часть головоломки, которую вам осталось понять, прежде чем вы, возможно, узнаете все, что вам нужно знать о Hyperlambda, — это «лямбда-выражения». Лямбда-выражения для лямбда-объектов — это то же самое, что селекторы jQuery или DOM для вашего JavaScript. Они позволяют вам ссылаться на наборы узлов в вашем коде DOM, чтобы затем использовать такие выражения в качестве аргументов для слотов, которые используют эти выражения для того, чтобы каким-то образом изменить ваш код DOM. Однако лямбда-выражение чрезвычайно просто для понимания, и на самом деле это всего лишь список перечислимых чисел, связанных вместе, чьи объединенные результаты дают один или несколько узлов. Ниже приведен пример использования слота [for-each] для перебора некоторого набора узлов и регистрации его значений.

.data
   item1:Hello from Item1
   item2:Hello from Item2
   item3:Hello from Item3
for-each:x:@.data/*
   log.info:x:@.dp/#

Первое вышеприведенное выражение можно найти в нашем узле [for-each], и оно выглядит следующим образом: @.data/*. Это выражение в основном говорит о следующем.

Найти первый вверху узел с именем «.data», а затем вернуть все его дочерние узлы

На этом этапе может помочь понять, что выражение имеет "итераторы", и каждый итератор отделен от предыдущего итератора символом /. Следовательно, это выражение имеет два итератора, один из которых начинается с символа @, подразумевая 'найти первый узел с именем xxx', где 'xxx' — это то, что следует за символом @. Следующий итератор — это итератор *, говорящий, по сути, 'дайте мне все дочерние узлы узлов, выданных предыдущим итератором'.

Внутреннее устройство цикла [for-each] снова заключается в том, что он будет вызывать своих дочерних элементов как лямбда-объект один раз для каждого узла, полученного в результате его выражения. узел [.dp], подразумевающий "указатель данных", позволяющий лямбда-объекту внутри цикла for-each обращаться к текущему повторяемому узлу по ссылке.

Последняя часть имеет решающее значение для понимания, поскольку цикл [for-each] позволяет своему лямбда-объекту изменять узлы, которые он перебирает, поскольку узлы передаются по ссылке, подразумевая ». семантика указателя». Вот почему нам нужно использовать странный итератор # внутри нашего цикла [for-each] для получения значения текущего итерируемого узла по ссылке, так как узел, который мы итерируем внутри нашего [for-each] можно найти в value самого узла [.dp].

В Hyperlambda существует целый ряд различных итераторов, и вы можете найти большинство из них ниже.

  • * Извлекает все дочерние элементы предыдущего результата
  • # Получает значение своего предыдущего результата как узел по ссылке
  • - Извлекает «младшего брата» своего предыдущего набора результатов (предыдущий узел)
  • + Извлекает «старшего брата» своего предыдущего набора результатов (следующий узел)
  • . Извлекает родительский узел (узлы) предыдущего набора результатов.
  • .. Извлекает корневой узел
  • ** Извлекает потомка своего предыдущего результирующего набора с помощью алгоритма «сначала в ширину».
  • {x} Экстраполированное выражение, которое будет оцениваться при условии, что оно дает один результат, заменяя себя значением любого узла, на который оно указывает.
  • =xxx Извлекает узел со значением «xxx», при необходимости преобразуя его в строку.
  • [n,n] Извлекает подмножество своего предыдущего набора результатов, подразумевая, что «от, до» означает [n1,n2›
  • @xxx Возвращает первый узел до в своей иерархии, который соответствует заданному xxx в его имени.
  • n (любое число) Возвращает n-й дочерний элемент предыдущего набора результатов.

Подведение итогов

Если у вас сейчас болит голова, пожалуйста, поймите, что с этого момента и далее становится только легче. Лямбда-выражения, вероятно, являются самым сложным предметом, существующим в Hyperlambda, поскольку для их воображения требуются отличные навыки визуализации. Однако, по сути, они такие же, как селекторы DOM из HTML или выражения XPath из XML.

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

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

Гиперлямбда была создана не для того, чтобы вы ее понимали, она была создана для того, чтобы ваш КОМПЬЮТЕР мог понять…

"Читать далее"