True — экспериментальный язык, где программа читает и меняет саму себя

—

от автора

True — язык программирования, где программа есть цикл, а код программы — лента кубитов (строк).

Simple — кроссплатформенный интерпретатор на Python 3 + Tkinter. Простой, без зависимостей.

Статус: Проект экспериментальный, на стадии MVP. В общем и целом, True — полноценный язык с собственной концепцией, и может развиваться как самостоятельный язык.

Идея

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

Программа здесь лента строк (я называю их кубитами). 

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

Программа одновременно и источник данных, и инструкции для выполнения. Нет отдельного кода и данных — есть кубиты, которые агент читает и переставляет.

Агент — не внешний интерпретатор, а часть файла .cycle. Он исполнитель и данные одновременно: строка Mr.Green, ... — такая же строка программы, как и все остальные, но именно она читает остальные.

Одна и та же логика на четырёх языках

True (main.cycle):

Mr.Green, #5fb85f | Data as <condition> | Aim: 1Поднимайся на лифте Mr.Green :)6 = max1 = floor1 = dir= liftdir > 0 ? floor =>| lift:y(, ):floordir < 0 ? lift:y(, ):last  -> ::nothingfloor == max ? -1 => dirfloor == 1 ? 1 => dirfloor + dir => ::math => floor

(Здесь => — копирование, -> — перемещение, ? — условие)

Python:

max_floor = 6floor = 1dir = 1lift = []while True:    if dir > 0:        lift.append(floor)    if dir < 0 and lift:        lift.pop()    if floor == max_floor:        dir = -1    if floor == 1:        dir = 1    floor = floor + dir    print(f"floor={floor} dir={dir} lift={lift}")

Lisp (Scheme):

(define max-floor 6)(define floor 1)(define dir 1)(define lift '())(define (step)  (when (> dir 0) (set! lift (append lift (list floor))))  (when (and (< dir 0) (not (null? lift))) (set! lift (reverse (cdr (reverse lift)))))  (when (= floor max-floor) (set! dir -1))  (when (= floor 1) (set! dir 1))  (set! floor (+ floor dir))  (display (list floor dir lift)) (newline))(let loop () (step) (loop))

Rust:

fn main() {    let max_floor = 6;    let mut floor = 1;    let mut dir: i32 = 1;    let mut lift: Vec<i32> = Vec::new();    loop {        if dir > 0 { lift.push(floor); }        if dir < 0 { lift.pop(); }        if floor == max_floor { dir = -1; }        if floor == 1 { dir = 1; }        floor += dir;        println!("floor={} dir={} lift={:?}", floor, dir, lift);    }}

Python, Lisp и Rust здесь реализуют ту же логику, но не читают и не меняют свой исходный код. True делает это на каждом шаге — программа самомодифицируется: агент меняет строки, memory отражается в тексте, <type> обновляется. Это отличие True от императивных языков: программа = данные + инструкции в одном.

Ключевые идеи

1. Кубит = строка

Строка — кубит. Её значение зависит от наблюдателя (агент).

На каждом шаге агент:

  • читает строку target (тип, значение),

  • выполняет действие (если action / condition),

  • меняет lines (flush памяти),

  • меняет строку агента (Data as <type>).

2. Наблюдатель = агент = часть программы

Агент — первая строка .cycle:

Mr.Green, #5fb85f | Data as <condition> | Aim: 1
  • Mr.Green — имя,

  • #5fb85f — цвет,

  • Data as <...> — тип, который агент распознал (обновляется каждый шаг),

  • Aim: 1 — цель, условие при котором цель считается достигнутой (в ROADMAP)

3. Цепочки кубитов

Пустая строка ("") — граница блока. Когда агент определяет тип первого кубита в цепочке, вся цепочка до separator срабатывает вместе как один блок этого типа.

Фрагмент реальной программы (main.cycle):

Mr.Green, #5fb85f | Data as <condition> | Aim: 1dir > 0 ? floor =>| lift:y(, ):floordir < 0 ? lift:y(, ):last  -> ::nothingfloor + dir => ::math => floor
  • dir > 0 ? ... и dir < 0 ? ... — один блок condition (пустая строка — граница).

  • floor + dir => ... — отдельный блок action (после separator).

Это позволяет группировать логику без скобок и определять тип всей цепочки определив только один кубит.

4. Оси данных

Контейнер может быть осью — списком:

Синтаксис

sep по умолчанию

Что

name:x(sep):i

"" (символы)

горизонталь

name:y(sep):i

"\n"

вертикаль

Разделитель оси можно переопределять.

Пример:

1, 2, 3 = liftlift:y(, ):last -> ::nothing

→ lift = "1, 2" (удалён последний элемент).

Оси — это способ интерпретации данных\кубита.

5. Расширения (вида ::name)

  • ::math — арифметика (+ - * / % ^ == != && ||),

  • ::nothing — удаление (-> удаляет, => — no-op).

Где посмотреть

  • github.com/e39din/True — репозиторий с доками и кодом

  • Демка:

    Видео Title

    Видео Title

Философия

  • Кубит = строка — данные в чистом виде, тип данных и как с ними работать определяет агент.

  • Наблюдатель = агент = часть программы — исполнитель и данные одновременно.

  • Программа читает и меняет саму себя — отличие от императивных языков.

  • Цепочки кубитов — группировка без скобок.

  • Оси данных — работа с данными как с геометрической фигурой.

  • Программа как цикл — программа циклична (можно остановить инструкцией).

  • ::name — функции расширения, встроенные или скомпилированные модули.

  • Наглядность процесса исполнения — живая обратная связь.

True v0.9.6. Simple v0.16.3.

Буду рад вашей обратной связи, добро пожаловать к обсуждению 🙂

ссылка на оригинал статьи https://habr.com/ru/articles/1103660/