Logo

26 января 2014 г.

Общий и чистый вызовы

Рассмотренная ранее трактовка параметров функций в Канторе объединяет понятие вызова функции с трактовкой порожденных функций как синонимов. На уровне модели (байт-кода) обобщенная форма обращения к функциям носит название общего вызова.

Обращение к чистым функциям, четко разделяемое на левую и правую части, может быть записано в альтернативной, более привычной форме, — при помощи оператора сопоставления (знака равенства). Форма записи в виде оператора сопоставления называется в Канторе чистым вызовом.

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

Предметно-ориентированные языки

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

Предметно-ориентированные языки как подключаемые модули

Технология подключаемых синтаксических модулей (plugins) уже была опробована на вики и хорошо себя зарекомендовала, обеспечив нужную расширяемость и гибкость. Разрабатывая язык общего назначения, хочется и его сделать его максимально расширяемым, для чего и примени́м механизм модулей, подключаемых к компилятору и отекстовщику.

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

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

Как и в вики, для подключаемых языков в Канторе выделена специальная синтаксическая конструкция.

Базовый синтаксис

Поскольку подключаемые модули пока могут реализовывать только описательные языки, им предлагается резервировать мнемонические символы, — они станут тегами предметно-ориентированного описания:
{тег предметно_ориентированное_описание тег}

Текст

Минимальным предметно-ориентированным «языком» является простой текст, — его модуль должен лишь уметь разбивать входной поток на отдельные строки в соответствии с правилами окружения, из которого был запущен компилятор. Мнемоническим тегом текста является апостроф:
txt = {'
  Это блок простого текста в естественном виде на Канторе.
  Сюда можно вписывать цитаты великих людей, если есть что вспомнить.

  Компилятор признаёт только одного великого человека — программиста.
'};
В примере описана функция txt, возвращающая объект типа :Core:Text, состоящий из четырех текстовых строк и имеющий предметно-ориентированную запись. Без модуля пример будет выглядеть так:
txt = new :Core:Text of
  += 'Это блок простого текста в естественном виде на Канторе.';
  += 'Сюда можно вписывать цитаты великих людей, если есть что вспомнить.';
  += '';
  += 'Компилятор признаёт только одного великого человека — программиста.';
end;

Вики

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

Мнемоническим символом вики-разметки является знак равенства:
wk = {=
  == Это вики-заголовок ==
  Сюда тоже можно вписывать цитаты, если --хочется //отжечь//-- есть что вспомнить.
=};
Как и в случае с текстом, получаемый результат проще всего продемонстрировать кодом на Канторе в отсутствие подключаемого модуля вики-разметки (имена классов и свойств на данный момент условны):
wk = new :Core:Wiki:Document of
  += new :Core:Wiki:Block of
    Heading = True;
    += new :Core:Wiki:Text of
      += 'Это вики-заголовок';
    end;
  end;
  += new :Core:Wiki:Block of
    += new :Core:Wiki:Text of
      += 'Сюда тоже можно вписывать цитаты людей, если ';
      += new :Core:Wiki:Text of
        Style = Strikeout;
        += 'хочется ';
        += new :Core:Wiki:Text of
          Style = Emphasis;
          += 'отжечь';
        end;
      end;
      += ' есть что вспомнить';
    end;
  end;
end;

HTML, RTF, TeX

Подключение модулей HTML, RTF и TeX предполагается аналогичным образом.

За HTML зарезервированы символы < и >, а набор классов HTML в Канторе планируется сделать полностью соответствующим W3C DOM. Вероятно, возможности модуля HTML будут расширяться по мере реализации функциональности браузера на Канторе, постепенно вбирая в себя CSS, JavaScript и пр.

За RTF и TeX зарезервирован один и тот же мнемонический символ — \ (обратный слеш). Разрешение этой коллизии и проработка остальных деталей реализации оставлены на будущее.

Неописательные языки

Уже говорилось, что технология предметно-ориентированных языков охватывает только описательные языки (либо языки, реализуемые через описательные, что может быть справедливо для JavaScript). Это логично, поскольку упрощение синтаксиса наиболее востребовано в специализированных (предметных) областях и не должно затрагивать базовую парадигму разработки на Канторе.

Теоретически можно было бы расширить синтаксис Кантора и предусмотреть вставку программных блоков на каком-либо другом языке, но это видится автору нецелесообразным.

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

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

Поэтому расширение синтаксиса блоками на других языках программирования не планируется (за исключением ассемблеров, вопрос с которыми еще не решен). В качестве альтернативы возможна эвристическая компиляция исходных текстов на других языках (Delphi, Си, Haskell и др.) в байт-код Кантора, работающая только в одном направлении, с дальнейшей отекстовкой и просмотром уже в синтаксисе Кантора. Есть гипотеза, что просмотр «чужих» библиотек в синтаксисе Кантора может оказаться даже удобнее, чем оригинальный код, особенно с целью изучения и анализа.

16 января 2014 г.

Параметры функций

Концепция параметров функций в Канторе довольно сильно отличается от общепринятой как в теории, так и на практике. Виновница несовместимости — фрактальная модель, в рамках которой переменные и функции объединились в одну сущность, а доступ к параметрам идет не по значению и ссылке, а на прием, возврат и мутацию, что отдаленно напоминает концепцию триггеров в СУБД.

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

Прием, чистота, мутация

Параметры функций в Канторе делятся на три вида — по способу доступа к ним:
  • Входные параметры не имеют ключевого слова. Функция, имеющая только входные параметры, является приемником. Будучи описанной внутри класса, функция-приемник становится свойством-приемником и получает возможность изменять контекст класса или объекта.
  • Выходные параметры обозначаются ключевым словом out. Наличие хоть одного выходного параметра делает функцию чистой и запрещает изменять контекст класса или объекта, если функция описана как свойство.
  • Мутирующие параметры или параметры-переменные обозначаются ключевым словом var. Наличие хоть одного мутирующего параметра делает всю функцию мутирующей — позволяет ей изменять контекст (как для приемника), но делает невозможным обращение к функции при помощи оператора присваивания, разрешая только общий вызов. Наличие var-параметров имеет наивысший приоритет при определении вида функции.
Таким образом, наличие тех или иных параметров накладывает ограничение на функцию целиком, порождая соответственно функции-приемники, чистые функции и мутирующие функции. Функции без параметров, в других языках называемые процедурами, в Канторе являются также мутирующими — var-функциями.

Именованные и анонимные параметры

Параметры функций могут быть как именованными, так и анонимными. Анонимными чаще всего являются out-параметры чистых функций, поскольку их реализация может быть описана или одним выражением, или при помощи оператора return, возвращающего значения позиционно и анонимно.

Пример с числом Авогадро из предыдущей статьи может быть записан в эквивалентных формах с ключевым словом out:
out avogadro = 6.022e23;  // неявный анонимный параметр
avogadro(out) = 6.022e23; // явный анонимный параметр
Форма с параметром в скобках является номинативной — именно так хранится функция в байт-коде. Прочие формы записи — синтаксический сахар.

Функция подсчета молярной массы, имеющая входной параметр, в полной форме будет выглядеть так:
mole(out; :Core:Real atomicWeight) = atomicWeight * avogadro;
Несмотря на наличие входного параметра atomicWeight, анонимный выходной параметр делает ее чистой, out-функцией.

Обе функции можно записать в эквивалентной форме с оператором return:
avogadro(out) of
  return 6.022e23;
end;

mole(out; :Core:Real atomicWeight) of
  return atomicWeight * avogadro;
end;
В байт-коде все формы записи идентичны, при отекстовке можно будет выбрать предпочитаемую.

15 января 2014 г.

Функции как синонимы

Реализация функциональной парадигмы в Канторе испытала сильное влияние SQL. SQL-запросы истолкованы автором как чистые функции, синонимы внутри select — как замыкания, а сам SQL признан самым популярным языком функционального программирования и годным источником заимствований. Простота объявления локальных имен, взятая из SQL, получила условное наименование программирования через синонимы.

Синонимы в SQL

Программиста на любом императивном языке, будь то Паскаль или Си, поначалу удивляет простота объявления синонимов полей и таблиц в запросах и командах SQL:
select
  a.code, b.subcode, a.name, b.name subname
from
  data a,
  subdata b
where
  a.code = b.code;
В этом примере subname — синоним поля subdata.name, а a и b — синонимы таблиц data и subdata. Синонимы обладают всеми атрибутами замыканий: описываются по месту использования, не требуют присваивания им значения, и, что самое важное, не создают накладных расходов на выполнение запроса, что подтверждается планом СУБД.

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

Чистые функции

В языке Кантор любое выражение является чистой функцией. Функции можно дать имя, сопоставив ей идентификатор, имеющий тот же смысл, что и синоним в SQL:
avogadro = 6.022e23;
sodium = 22.89;

mole[:Core:Real atomicWeight] = atomicWeight * avogadro;
moleOfSodium = mole[sodium];

megabyte = 1K**; // 1024²
В Паскале объявление аналогов функций avogadro, sodium и megabyte считалось бы объявлением констант при помощи константных выражений. В Канторе функции первичны, а константы являются частным случаем чистых функций. Чистота функций означает, что:
  • Сопоставление выражения функции делается один раз — при описании. Знак равенства тут нужно трактовать как символ синонима, а не как оператор присваивания.
  • Использование функций не влечет дополнительных накладных расходов. В самом простом случае компилятор вставляет тело функции в место ее вызова.
В SQL объявления аналогов avogadro, sodium и megabyte считались бы константными таблицами, а mole и moleOfSodium — представлениями.

Как принято в функциональных языках, тип результата функции может быть опущен, что задействует вывод типов компилятором. В нашем примере функция megabyte получит тип :Core:Int[32], а остальные функции — тип :Core:Real.

Функции, реализованные памятью

Кантор — функциональный язык системного программирования, что заставляет ввести в него понятие переменной непосредственно, не пряча за абстракциями-обертками. Чтобы не сломать первичность функций и не вносить исключений в правила, для переменных в Канторе принята оригинальная трактовка:
Переменные являются функциями, реализованными памятью.  
Превратить функцию в переменную можно, «защелкнув» ее ключевым словом var:
var substance = moleOfSodium;
Память позволяет сопоставлять значение функции много раз, что вполне ожидаемо дает побочный эффект. Сопоставление значений переменным является полноценным присваиванием, но записывается как и для чистых функций — знаком равенства:
substance = mole[15.99]; // oxygen
substance = mole[55.85]; // ferrum
То есть, синтаксически и семантически присваивание является частным случаем сопоставления значения функции, и трактовка знака равенства как объявления синонима или присваиваения зависит от того, что стоит в левой части сопоставления — чистая функция или переменная.

В SQL аналогом переменных являются таблицы, а аналогом переменных с начальным значением — материализованные представления, состоящие из таблицы и связанного с ней представления одновременно.