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

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

Демо-видео: https://dzen.ru/video/watch/6aebbfeaedfee2293a3640bf

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

Идея

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

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

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

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

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

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

True (main.cycle):

Mr.Green, #5fb85f | Data as <condition> | Aim: 1
Поднимайся на лифте Mr.Green :)

6 = max
1 = floor
1 = dir

= lift

dir > 0 ? floor =>| lift:y(, ):floor
dir < 0 ? lift:y(, ):last  -> ::nothing

floor == max ? -1 => dir
floor == 1 ? 1 => dir

floor + dir => ::math => floor

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

Python:

max_floor = 6
floor = 1
dir = 1
lift = []

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: 1
dir > 0 ? floor =>| lift:y(, ):floor
dir < 0 ? lift:y(, ):last  -> ::nothing

floor + 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 = lift
lift:y(, ):last -> ::nothing

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

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

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

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

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

6. Отсутствие типов (typeless)

  • Все есть строка (данные)

  • Агент решает как интерпретировать данные

  • Получается "типы данных" меняем на "типы установок агента"

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

Философия

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

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

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

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

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

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

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

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

Чем-то True идеологически похож на Lisp по работе с данными, самомодификации и лаконичности синтаксиса, и в то же время отличается цикличностью, явными агентами и определением типов.

True v0.9.6. Simple v0.16.3.


=== Добавлено:

Чтобы прояснить неоднозначные моменты:

True + Simple - MVP, концепт который может развиваться и найти свое применение в каких-то нишах, частично или полностью

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

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

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

Сейчас показан один цикл и один агент, с развитием естественно будет добавить несколько циклов и несколько агентов, плюс ходить и по другим данным, текстам, DB, API, файлам и т.п. Расширение .cycle нас не ограничивает, оно скорее для удобства создания программ с инструкциями чисто на языке True

Меня попросили сделать простой пример, хорошая идея:

Mr.Green, #5fb85f | Data as <type> | Aim: 1

1 = a
b
c

a => b
b -> c

Описание как их видит агент Mr.Green (по умолчанию)

  1. На себя не смотрит, смотрит на то что под ним и видит:

  2. Пустой неименованный контейнер

  3. Строка 1 в именованном контейнере a

  4. Пустая строка в именованном контейнере b

  5. Пустая строка в именованном контейнере c

  6. Пустой неименованный контейнер

  7. Действие копирования (=>) значения контейнера a в b ( a: "1"; b: "1" )

  8. Действие перемещения (->) значения контейнера b в c ( b: ""; c: "1" )

=============================



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

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Полетит?
12.5%Ага :)2
87.5%Неа14
Проголосовали 16 пользователей. Воздержались 5 пользователей.