Устный и письменный язык, понятный как человеку, так и компьютеру. Пусть в просторечии это будет называться Reverse.

Для всей этой статьи код на языке будет представлен в виде блоков кода, где ## обозначает однострочный комментарий (текст, не зависящий от языка).

Начнем с элементов языка.

Грамматика

Грамматика (или синтаксис) — это способ написания языка и правила, которым он должен следовать. Все предложения на языке (или выражения) должны заканчиваться символом точки (.). Предложения включают несколько слов, разделенных одним или несколькими пробелами. Слова в языке могут быть как вещью, так и оператором. Начнем с операторов.

Операторы

Операторы — это слова, которые воздействуют на окружающие их вещи. Этот акт работы известен как операция. Операция всегда будет оцениваться как вещь.

Грамматика для операции выглядит следующим образом:

thing operator thing.

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

operator thing.

Это то, что вы могли бы назвать унарной операцией (в отличие от бинарной операции).

Все операторы в Reverse следующие:

is
of
to
in
as
and

Эти операции будут подробно изучены по ходу дела.

Порядок действий

Порядок операций обычно следует приоритету слева направо:

((thing operator thing) operator thing).

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

Вещи

Вещь является фундаментальным элементом языка. Лучше всего вещь можно описать следующим образом:

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

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

123456. ## A number
"String of characters". ## A string

В приведенном выше случае либо число, либо строка.

Вещь также может быть определена с помощью этих литералов и оператора is:

mything is 123.

После этого вещь mything теперь является представлением вещи 123.

Вещи также могут содержать другие вещи, используя оператор in для доступа к потенциальным вещам внутри другой вещи (если указанная вещь существует или должна быть определена):

myotherthing in mything is 456. ## Sets an inner thing
myotherthing in mything. ## Gets the inner thing; evaluates to 456

Внутренние вещи могут быть идентифицированы либо по идентификатору вещи (строка символов, которая является именем вещи), либо по индексу:

0 in mything. ## Gets the first inner thing
1 in mything. ## Gets the second inner thing
## ...

Индекс — это число, которое представляет порядок внутренней вещи.

Эти индексы можно создать с помощью оператора and:

'one' and 'two'.

В этом случае выражение будет оцениваться как вещь, которая имеет две внутренние вещи ‘one’ и ‘two’ с индексами 0 и 1 соответственно. Мы называем этот тип вещей набором вещей.

Операция and также будет оценивать одно измерение набора вещей:

'one' and 'two' and 'three'.
## A set of things ['one', 'two', 'three'] is the result
## Not [['one','two'], 'three']

Двигаемся дальше... Одним из самых интересных типов вещей является функция.

Функции

Функции — это типы вещей, которые могут определять отношение между вводом и выводом.

Функции можно вызывать с помощью оператора to:

to f. ## Invokes the function called "f"

Функции могут быть вызваны с вещью в качестве входных данных:

x to f. ## Invokes the function "f" with input "x"

Несколько входных данных могут быть переданы вызову функции с помощью набора:

x and y and z to f. ## Passes the set of things [x, y, z] to f

Функции могут быть выражены с помощью оператора of:

23 of x. 
## Evaluates to a function with one input, `x` and an output of `23`

Вещи могут быть определены как функции с помощью старого доброго оператора is:

f is 23 of x.

Сейчас самое время вернуться к порядку операций и исключению, о котором мы упоминали ранее. Причина: is и of действуют в том же порядке.

Особый заказ есть и…

С этого момента я буду чередовать обратный код и JavaScript, чтобы помочь в понимании.

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

x is y is z.
## Is not
((x is y) is z)
## Rather it is
(x is (y is z))
## Similarly
w is x is y is z
## Is not
(((w is x) is y) is z)
## But rather it is
(w is (x is (y is z)))
## Also note
x is y to f
## Is not
(x is y) to f)
## But rather
(x is (y to f))

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

Позвольте мне показать вам примеры, используя JavaScript в качестве ссылки:

x is y.
var x = y;

x is y is z.
var x = (y = z);

x is y to f.
var x = f(y);

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

Пример каррирования в JavaScript:

curry(x)(y);

Каррирование в обратном порядке достигается только путем сохранения результата первого вызова функции в другой вещи перед вызовом этой вещи. Вот пример, все еще на JS:

var what = curry(x);
what(y);

Вот как тот же код выполняется в обратном порядке:

what is x to curry.
y to what.

Как видите, сначала мы определяем what как результат x to curry, а затем вызываем what с вводом y. Все это можно сделать в одном предложении благодаря порядку оператора is:

y to what is x to curry.
## Order:
(y to (what is (x to curry))).

Теперь вы можете видеть, как is помогает «обратить» (каламбур) порядок операций. Если порядок операций не изменился, то:

y to what is x to curry.
## Would become:
(((y to what) is x) to curry).

И это вызовет ошибку, потому что what не определено. И даже если what было определено, то как определить оценку y to what с оператором is как x? Это просто не имело бы смысла, поэтому is меняет порядок операций на противоположный.

Что насчет?

Теперь of тоже жадный. Он будет вычислять все левое выражение целиком вплоть до начала выражения, пока не оценит себя. Это как обратное число is.

f is x is 23 of x.
## Becomes
(f is ((x is 23) of x))
## Not
(f is (x is (23 of x)))

Обратите внимание, что of заставит вычислить второе is в x is 23 до того, как of заставит вычислить свое левое выражение. Это связано с тем, что порядок операций для is и of меняется местами между двумя операторами: первый is возьмет все с правой стороны, тогда последний of возьмет все с левой стороны своей операции, затем второй is возьмет все с правой стороны от себя, затем предпоследний of возьмет все с левой стороны… и так далее:

f is x is y is 23 of y of x.
## the first `is` evaluate left-hand
f is (x is y is 23 of y of x).
## the last `of` evaluates right-hand
f is ((x is y is 23 of y) of x).
## second `is` evaluates
f is ((x is (y is 23 of y)) of x).
## second to last `of` evaluates
f is ((x is ((y is 23) of y)) of x).

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

Как это выглядело бы в JavaScript?

f is ((x is ((y is 23) of y)) of x).
## becomes
var f = (x) => (x = (y) => (y = 23))
## Or if you fancy ES5
var f = function(x){
  return x = function(y){
    return y = 23;
  }
}

Краткое примечание: вы можете опустить правостороннее выражение в операторе of:

f is 23 of.
## Is the same as:
var f = function(){ return 23; };
## And
f is f is 23 of of.
## Becomes
(f is (f is (23 of) of)).
## or in JS
var f = function(){ return var f = function(){ return 23}; };

Таким образом, мы можем иметь функции без входных данных.

Но что, если мы хотим выполнять анонимные функции; функции без имен? Скажите, что вы хотели сделать:

(function(){
  return 23;
})()

Вы не могли сделать:

to 23 of.
## Because that means
(to 23) of.
## Which in JS would be
function(){
  return 23();
}

Что не имело бы смысла и было бы ошибкой. Что ж, чтобы решить эту проблему, нам понадобится способ сохранить значение функции, прежде чем мы сможем ее вызвать. Это похоже на нашу проблему каррирования! Помните, как мы это решили?

var what = function(){ return 23; };
what();

В обратном порядке это будет выглядеть так:

what is 23 of.
to what.
## Or in one expression:
to what is 23 of.

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

Вот и все, что можно было сказать о порядке is и of.

Сфера!

Что насчет размаха? Какой размах?!

Область действия аналогична области действия JavaScript: функциональная область.

x is 23. ## let x be 23
f is x of. ## function has access to x outside of it
to f. ## returns 23
x is 11.
to f. ## return 11
f is x of x.
23 to f. ## returns 23, even though the outside x is 11

Как вы определяете вещи в теле функции? Как мне это сделать:

var f = function(){
  var secret = 11;
  return function(){ 
    return secret;
  }
}

Вы бы не стали. Это глупо. Просто сделать:

f is 11 of of.

Какая функция возвращает функцию, возвращающую 11.

Но что, если вы хотите изменить состояние секретности на основе внешней функции?

var f = function(parameter){ 
  var secret = parameter;
  return function(){
    return secret;
  }
}

Что ж… Это также глупо, потому что вы могли просто сделать:

f is parameter of of parameter.

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

f is parameter and 2 to multiply of of parameter.
## In JS it would look like
var f = function(parameter){
  return function(){ 
    parameter * 2; 
  };
}

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

Как насчет функций высшего порядка?

var f = function(x, y){
  x(); // Do one thing
  y(); // Do another
}
## Easy
f is 
  to x and to y
of x and y

Разве я не забыл упомянуть, что вы можете выполнять деструктуризацию в правой части оператора of? Виноват. Ну ты можешь! И это очень удобно.

Также обратите внимание, что f возвращает набор результатов вызова x и результатов вызова y. Что хорошо, если вы хотите передать этот набор другой функции, которая может что-то с ним сделать.

Вывод.

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

Я только забыл упомянуть оператора as. Это просто способ определить идентификатор в наборе:

1 as foo and 2 as bar.
## Is like this in JS:
{foo: 1, bar: 2}

Единственная разница между набором и объектом в JS заключается в том, что элементы индексируются в JS. Впрочем, я еще не решился на это…

Таким образом, as делает удобным иметь помеченные входные данные для функций:

f is 
  dividend and divisor to divide to square
of dividend and divisor.
1 as dividend and 2 as divisor to f.

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

В любом случае, если вы зашли так далеко… Тогда, возможно, вам захочется заняться чем-то другим. Спасибо за чтение!