Русский язык программирования
Это руководство описывает русскоязычный язык программирования, основанный на идеях из расширения синтаксиса Scheme readable.
Семантика языка на данный момент полностью унаследована от Racket, вплоть до полной обратной совместимости: из этого языка можно вызывать любые функции и синтаксические конструкци Racket, а из Racket можно вызывать модули на этом языке.
Для включения синтаксиса данного языка просто укажите в модуле Racket в первой строке
#lang 1
или
#!1
Второй вариант рекомендуется при использовании русского языка для написания программы.
1 Отличия от Racket
Эта глава предназаначена для тех, кто умеет программировать на Scheme и/или Racket. Остальные могут её пропустить и перейти к следующей.
На этом языке можно писать как на Racket с упрощённым синтаксисом. Обратная совместимость поддерживается почти полностью, за исключением строчных комментариев и квадратных и фигурных скобок. Если в Racket использовалась ";", то здесь для строчных комментариев необходимо использовать "–", так как ";" используется в других синтаксических конструкциях, которые будут описаны ниже. Квадратные иф фигурные скобки также нельзя использовать вместо круглых, так как они несут другой синтаксический смысл.
То есть, например, программа
#!1 (letrec ((is-even? (lambda (n) (or (zero? n) (is-odd? (sub1 n))))) (is-odd? (lambda (n) (and (not (zero? n)) (is-even? (sub1 n)))))) (is-odd? 11))
#!1 список 1 2 3 4 5 6
#!1 список 1 2 3 4 5 6
Если на одной строке есть несколько элементов, разделённых пробельными символами, то это список.
Если следующая строка начинается с большего отступа, чем текущая, то это элемент —
#!1 список 1 2 список 3 4 5 список 6 список 7 8
Также есть специальная конструкция для списков, первым элементом которых тоже является список. В этом случае длядополнительного отступа можно использовать ";". Либо её же можно использовать для разделения списка на подсписки.
(let ((x 1) (y 2)) (f x y))
#!1 let ; x 1 y 2 f x y
#!1 let (x 1; y 2) f x y
Синтаксическое правило выглядит так: если в списке встречается ";", то список разделяется на подсписки, как если бы вместо ";" был перенос строки с сохранением отступа.
Таким образом, последовательности элементов "x 1" и "y 2" становятся вложенными списками.
#!1 letrec ; is-even? lambda (n) or zero? n is-odd? sub1 n is-odd? lambda (n) and not zero? n is-even? sub1 n is-odd? 11
Есть ещё одна синтаксическая конструкция, заимствованная из Haskell, позволяющая сократить количество строк не добавляя скобок. Символ "$" показывает, что элементы справа от него являются списком, который должен быть подставлен на место этого символа.
#!1
список 1 2
список 3 4; 5
список 6 $ список 7 8
#!1 letrec ; is-even? $ lambda (n) or zero? n is-odd? $ sub1 n is-odd? $ lambda (n) and not $ zero? n is-even? $ sub1 n is-odd? 11
Таким образом получаем наглядное представление программы, которое не перегружено скобками.
Для упрощения чтения программы также добавлено ещё несколько синтаксических конструкций, которые позволяют сделать текст программы более похожим на широко распространённые языки программирования.
Если перед скобкой нет пробела, то включается особый алгоритм обработки. Для круглой скобки элемент перд скобкой добавляется в голову списка. Элементы внутри спиcка можно (но не обязательно) разделять при помощи ";".
#!1
список(1; 2; список 3 4; 5; список 6 $ список 7 8)
Так можно записывать в одну строку вызовы функций с аргументами, которые являются вызовами функций. Кроме того такитм образом удобно вызывать каррированные функции Вместо (((f 5) 6) 7) будет f(5)(6)(7)
Для квадратной скобки конструкция преобразуется в инструкция доступа к коллекции (массиву/списку/хэшу).
Вместо (vector-ref a 5) можно просто писать a[5].
А вместо (vector-ref (vector-ref a 5) 6) —
Для фигурной скобки конструкция даёт возможность вызвать методы объекта.
(send window show #t) можно записать как window{show #t}. также можно использовать несколько вызовов как в send+.
(send+ (new point%) (move-x 5) (move-y 7) (move-x 12))
#!1
new(point%){move-x 5; move-y 7; move-x 11}
#!1
new(point%){move-x(5) move-y(7) move-x(11)}
Для удобства работы с арифметикой реализованы приоритеты бинарных операций. Если в списке обнаружена бинарная операция, то она становится в голову списка и получает элементы до и после неё как два аргумента-списка. Операцией считается любой индентификатор, который состояит только из !#$%&⋆+./<=>?@^~:*-
Оператор равенства реализован как == (вместо =), также реализованы // (как quotient), /= (неравно), ||, &&, % (как remainder).
#!1 a[5] + 2 * h['key]
Внимание: пробелы вокруг операций обязательны, так как 2*h, например, является нормальным именем переменной.
#!1 letrec ; is-even? $ lambda (n) n == 0 || is-odd? (n - 1) is-odd? $ lambda (n) n /= 0 && is-even? (n - 1) is-odd? 11