Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

[Перевод] Вы ещё пишете код слева направо? Тогда мы идём к вам

Дата публикации: 13-08-2026 09:05:25

Вам нужно в одном выражении использовать временный бит, а потом вернуть его в исходное состояние, не прибегая к дополнительным строчкам кода.Задача тянет на головоломку, но в мире двумерного синтаксиса у неё есть красивое решение — просто отзеркалить операцию строчкой ниже. Такой трюк напрямую моделирует обратимость вычислений из квантовой физики.Статья как раз об этом: как освоение второго измерения помогает чисто и наглядно записывать цепочки операторов, чистить мусор и даже строить 3-битный сумматор, который выглядит как единый двумерный блок. Читать далее

Основное содержимое страницы с новостью.

А ведь выражениям совсем не обязательно вытягиваться в струнку слева направо. Кто сказал, что то же a < b нельзя записать по вертикали?

79eac6b2cc25ec0cd996fe3bd8bfc9bc.png

Мы привыкли втискивать код в одномерную плоскость строки, но что будет, если освоить второе измерение? Разумеется, чтобы всё это закрутилось, среда разработки и парсер должны работать как единый слаженный механизм. Но главный вопрос: ради чего всё это? Давайте разберем несколько любопытных примеров.

❯ Функции от трёх аргументов

Трехаргументные (или тернарные) функции в инфиксной записи — зверь довольно редкий.

В том же Python, да и во многих других языках, можно связать оператором and сразу цепочку условий:

x and y and z

Но технически это лишь последовательное применение нескольких бинарных функций.

Даже идиома в Python, сокращающая (a < b) and (b < c) до изящного:

a < b < c

— по сути, всё та же комбинация.

А теперь знакомьтесь: забавный оператор andFlip, с которым я экспериментировал. Именно он наглядно показывает, зачем нужна настоящая трёхместная инфиксная запись. Вот как выглядит его суть:

def andFlip(args):
    if args[0] and args[1]:
        args[2] = not args[2]
    return args[2]

Он принимает два входных сигнала и, если оба истинны, инвертирует целевое значение.

Записать такую штуку традиционным инфиксным способом красиво просто невозможно. Но давайте всё же попытаемся.

Обозначим оператор andFlip символом @@. Как это будет выглядеть на практике?

Способ 1: традиционный

Можно каррировать andFlip: тогда инфиксный @@ принимает два аргумента и возвращает функцию, ожидающую третий:

(a1 @@ a2) a3

Что ж, сносно. Работать будет. Но…

Способ 2: экзотический

Забудьте на секунду привычные правила синтаксиса. Будь у меня волшебная палочка, я бы заставил тернарную запись выглядеть вот так:

7a81fd48c6ce155ce6f58afa01254313.png

Почему бы не задействовать ось Y, раз уж она у нас есть?

Выстраивать цепочки становится невероятно удобно:

267f00f95574075b7facf268bf22229a.png

В этой цепочке выражение x @@ y переключает флаг t1, а затем этот же t1 передается дальше — в t1 @@ z, который переключает t2.

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

Кстати, раз уж мы перешли в двухмерную плоскость, то вот эта запись:

1b7d8ebfb1b4cecaa3dd073ad8c3bb7c.png

Абсолютно эквивалентна такой:

c218184d0c17a7b19bf8d4b24dbdc0b3.pngПример из жизни: дверь курятника

Взгляните на автоматическую дверь, которую я поставил в курятнике.

Автоматическая дверь курятника (справа) и блок управления

Автоматическая дверь курятника (справа) и блок управления

С помощью фотодатчика и встроенных часов микроконтроллер отслеживает три параметра:

  • x — датчик освещенности зафиксировал порог рассвета/заката;

  • y — показания оставались стабильными в течение пяти минут;

  • z — за последнее время дверь не меняла своего положения.

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

e0d7db1bd26ea232e22240c9cb9380b9.gif

В основе контроллера курятника лежит ровно та же цепочка, что мы разбирали выше:

c3841da4592eef50ec5e07ba59954785.png

Вы спросите: а почему бы просто не написать x and y and z? Да потому что тогда дверь превратилась бы в послушное зеркало датчиков и тут же захлопнулась обратно, стоило бы условию хотя бы на миг пропасть. Оператор @@ же фиксирует состояние: дверь открылась — и всё, а промежуточное значение сохраняется в техническом бите‑черновике t1.

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

❯ Вертикальные цепочки

Изменчивая переменная t1 не позволяет назвать такое выражение «чистой функцией». Но можно ли обойти это ограничение? Способны ли мы сбросить t1 в исходное состояние, не выходя за рамки единого выражения?

Давайте разберем идею вертикальных цепочек на двух головоломках.

Задачка 1: сбросить t1 в ноль

Как уже говорилось, в предыдущих примерах переменная t1 меняет свое значение. Задача: как возвратить её к 0, чтобы со стороны выражение казалось чистым и неизменяемым? Соблазн просто дописать в конце t1 = 0 велик, но суть именно в том, чтобы сделать всё внутри одного двухмерного выражения.

Попробуйте решить сами, прежде чем листать дальше!


А вот и отгадка. Поскольку t1 сбрасывается повторением той же операции, которая её инвертировала, мы можем объединить выражения в единый двухмерный блок:

7f9f9e50b8a0ccec6d9ebc797662d435.png

Да уж, выглядит как магия.

Поток данных движется привычным образом: слева направо и сверху вниз. Если x и y истинны, первая строчка x @@ y переключает t1, а вторая x @@ y — возвращает его в исходное состояние. Если же условия не выполнены, t1 просто не затрагивается.

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

Задачка 2: вернуть временную переменную к исходному значению

А что если t1 изначально содержит неизвестное булево значение n? Задача усложняется.

992a7caf177365b0d42b7241d4de5232.png

Прошлый трюк для сброса t1 к исходному значению уже не пройдет.

Убедитесь сами: если t1 = 1, а x, y и z истинны, то t2 останется равным 0, что неверно.

652736c1e56f12e0e3b8482f8088ca3e.png

Так каково же решение?


Та‑дам!

4b3461eb4520e57b6b1080e4e7c12008.png

Выглядит гениально. Это единое 2D‑выражение корректно сбрасывает t1 обратно в n, выдавая при этом верный результат для t2.

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

Вот как эта схема выглядит в Qiskit:

from qiskit import QuantumCircuit, QuantumRegister

x = QuantumRegister(1, "x")
y = QuantumRegister(1, "y")
z = QuantumRegister(1, "z")
t1 = QuantumRegister(1, "t1")  # начальное неизвестное состояние n
t2 = QuantumRegister(1, "t2")  # цель, изначально 0

qc = QuantumCircuit(x, y, z, t1, t2)

qc.ccx(x, y, t1)
qc.ccx(t1, z, t2)
qc.ccx(x, y, t1)
qc.ccx(t1, z, t2)

Реализация на Qiskit воспринимается значительно тяжелее из‑за необходимости постоянного отслеживания переменных туда‑сюда.

Кстати, вот эквивалентная квантовая схема:

735c53f2273d0d9bc78ee0710332c522.png

Схема в чем‑то понятнее, но плохо масштабируется. А вот синтаксис двухмерного языка берет лучшее от обоих форматов.

❯ Конструирование новых операторов

Для начала познакомимся с младшим братом оператора @@. Одиночный @ принимает лишь одно условие: запись x @ y переключает y всякий раз, когда x истинно.

Имея в арсенале @ и @@, мы можем конструировать новые операторы прямо в пространстве. Слева от := задается двухмерная форма, а справа — её раскрытие:

ca2046a2a2a377c4b0a9fb4b12ab9ee2.png

Этот хитроумный оператор инвертирует b и c, если a истинно; затем переключает a, если оба результата оказались истинными. По сути, он вычисляет a ^ ((a^b) & (a^c)) и записывает результат в a. Это не что иное, как функция большинства (мажоритарный вентиль) для трех входов, — отсюда и название maj.

4935a1892cf2d52482e7ac31f6064489.png

И выбор maj далеко не случаен. Это вентиль MAJ из классической квантовой схемы сумматора с последовательным переносом, где мажоритарность значений (перенос, бит, бит) определяет следующий бит переноса.

Вы могли заметить, что maj оставляет за собой «мусор» в b и c (там сохраняются a^b и a^c) — ровно так же, как было с нашей переменной t1. Чтобы прибраться за собой, введем парный оператор uma (unmajority and add). Он восстанавливает a, отменяет мажоритарность c и прибавляет сумму к b:

d565170f381c534ed50dcb6ed879d0ec.png

Посмотрим, что произойдет, если объединить их в цепь.

❯ 3-битный сумматор

Теперь мы можем собрать полноценный 3-битный сумматор из трех вентилей maj, протягивающих перенос по шинам a. Финальный @ сбрасывает бит переноса на c3, а нижняя строчка операторов uma подчищает все промежуточные значения:

2abef9b2c1323e68c4229e4a4115db72.png

Перед нами законченный 3-битный сумматор в виде одного двухмерного выражения, которое само за собой убирает! В шинах b теперь записана сумма a + b, в c3 — бит переноса, а c0 и шины a возвращаются в исходное состояние. (Подайте c0 = 1 — и совершенно бесплатно получите a + b + 1.)

Обратите внимание, как верхняя и нижняя строки зеркально отражают друг друга. Верхняя часть погружается вправо до b0 и протягивает перенос вверх; нижняя — уходит влево к b2 и сворачивает вычисления. Общие метки a1 и a0 служат опорными точками, работая и на верхний maj, и на нижний uma. Точка . обозначает вертикальную связь с вышестоящей шиной (в данном случае a2). Цепочка переноса сшивается по вертикали: этап отмены вычислений соприкасается с этапом расчета — ровно как в наших головоломках.

❯ Экспресс‑обзор других пространственных языков

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

Befunge

Дедушка всех 2D‑языков Befunge (1993 год): указатель инструкций физически перемещается по сетке, а стрелки >v<^ задают его курс. Вывод «Hello World!» буквально рикошетит от границ:

2586b550605e1beb9b66ee13ad0a8de0.pngOrca

Orca — язык‑секвенсор для лайвкодинга, где каждая буква является оператором, считывающим соседние клетки: например, A складывает значения слева и справа и записывает результат прямо под собой. Знакомо выглядит, правда?

53c04c9a9daaac540f64212ef253c82e.pngRacket #2d

Вполне реалистичное расширение языка: #2dcond в Racket — это конструкция cond, вычисляемая в двух измерениях. Левый столбец проверяет условие b, верхняя строка — a, а исполняется клетка на их пересечении.

774ab0d59884de4bb7140bded0aef1c3.pngHexagony

Hexagony работает на шестиугольной сетке с вершиной вверху. Шесть указателей команд стартуют из шести углов. Вот как выглядит «Hello World»:

72d3056d3ca476ddf3b3fa3ae3ba398a.pngРелейная логика

Релейная логика (ladder logic) — язык, на котором ПЛК управляют целыми заводами (а при прямых руках — и дверью курятника). Каждая «ступенька» представляет собой релейную цепь, считываемую от шины к шине, а параллельные ветки работают как оператор ИЛИ. Классическая схема с самоблокировкой вычисляет Run = (Start OR Run) AND (NOT Stop):

4ce10fe44172c6a7762178f9a480d5a8.png

И отдельно отметим самый успешный пространственный язык всех времен — электронную таблицу, где каждая формула живет по 2D‑координатам и обращается к соседям.

❯ «Это вода»

Некоторые знают мое пристрастие к гипотезе Сепира — Уорфа, согласно которой язык определяет мышление:

  • У некоторых австралийских аборигенов нет понятий «лево» и «право» — только стороны света. Поэтому они всегда идеально ориентируются, где север.

  • В русском языке есть четкое разделение на «голубой» и «синий» (в отличие от английского blue), поэтому русскоязычные люди быстрее различают эти оттенки, когда они находятся на границе понятий.

  • В Haskell всё чисто функционально, поэтому ты начинаешь видеть монады буквально на каждом шагу.

Точно так же технологии определяют, какими становятся создаваемые нами языки программирования:

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

  • Стандартные клавиатуры заточены под английский язык и символы ASCII — и наше мышление замыкается в этих рамках.

Осознание собственных паттернов — полезная гимнастика для ума. Об этом говорил еще Дэвид Фостер Уоллес в своей знаменитой речи «Это вода». И хотя его выступление было не совсем про квантовую обратимость вычислений, а скорее про взросление и эмпатию, суть одна: ставя под сомнение привычные рамки, мы открываем дверь для принципиально новых идей.

Может быть интересно:Перейти ↩

Перейти

Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram‑канале 

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
148-кубитный гибридный симулятор Гровера на домашней видеокарте: пробиваем стены памяти и времени08.6104-06-2026
2Квантовый сапёр и квантовый тетрис: изучение квантовых феноменов через компьютерные игры0725-04-2026
3Костыль на костыле: как я больше двадцати лет лечил остатки вместо того, чтобы найти причину07.410-08-2026
4[Перевод] Паттерны доступа к данным, которые выбесят ваш процессор0703-07-2026
5Scientists make quantum time flow backward in stunning physics breakthrough05.8603-07-2026
6[Перевод] Доверьтесь компилятору: C++23 против трюков из 90-х010.427-07-2026
7Как квантовый компьютер изменит нашу жизнь: без формул и заумных ...5728-06-2026
8Ты не найдёшь эту ошибку. Потому что её нет в твоём коде. Как Self-describing API спасает от чужих рефакторингов5807-07-2026
9Как желание быстрее читать чужой код превратилось в войну с недетерминизмом LLM0528-06-2026
10Метафора квантовой механики глазами хобби-гейм-девелопера. Попытка понять квантовые штуки через алгоритмы поиска пути0522-06-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 9.01. Источник: habr.com.