Русский язык программирования
#lang 1 | package: russian-lang |
Это руководство описывает русскоязычный язык программирования, основанный на идеях из расширения синтаксиса 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
Если на одной строке есть несколько элементов, разделённых пробельными символами, то это список.
Если следующая строка начинается с большего отступа, чем текущая, то это элемент —
Также есть специальная конструкция для списков, первым элементом которых тоже является список. В этом случае длядополнительного отступа можно использовать «;». Либо её же можно использовать для разделения списка на подсписки.
(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)}
Для удобства работы с арифметикой реализованы приоритеты бинарных операций. Если в списке обнаружена бинарная операция, то она становится в голову списка и получает элементы до и после неё как два аргумента-списка. Операцией считается любой индентификатор, который состоит только из !#$%&⋆+./<=>?@^~:*- и не равен «...». Любой другой идентификатор можно сделать оператором добавив перед и после него символы «^». Например, (2 ^cons^ 3) то же самое, что (cons 2 3).
#!1 list (. +) 3
Оператор равенства реализован как == (вместо equal?) и === (вместо eqv?), также реализованы // (как quotient), /= (неравно), ||, &&, % (как remainder).
Внимание: пробелы вокруг операций обязательны, так как 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
2 Основы языка
Программа состоит из команд. Команда может быть вызовом функции, синтаксической конструкцией или определением переменной. Первая строка в программе определяет используемый язык программирования и является строкой «#!1».
#!1 вывести "введите имя: " имя = прочитать-строку() вывести "Привет, " ++ имя
2.1 Простые значения
Значения языка программирования включают числа, логические значения, строки и массивы байтов. В DrRacket и документации они выделены зелёным цветом.
10 2.5 1/3 10200000000000.0 5+6i 12345678123456781234567812345678
Бесконечные целые и простые дроби позволяют выполнять арифметические операции без потери точности и риска переполнения. Числа с десятичной точкой или экспонентой являются вещественными числами двойной точности и хранят только 15-17 знаков.
Логические значения — это истина и ложь. При проверках в логических операциях любое значение, не равное ложь трактуется как истина.
Строчные значения записываются между двойными кавычками. Для записи кавычк используется
последовательность символов «\"», для записи символа «\» —
"Привет!" "Автомобиль \"Москвич\"" "你好"
Когда константа выводится в окне интерпретатора, как правило, она имеет тот же вид, в котором она была введена, но иногда при выводе происходит нормализация. В окне интерпретатора и в документации результат вычислений выводится синим, а не зелёным, чтобы было видно, где результат, а где введённое значение.
> 1.0000 1.0
> "\u0022ok\u0022" "\"ok\""
2.2 Выражения
Выражения записываются в виде последовательности слов, разделённых пробельными символами. Слово может быть оператором, если состоит только из символов «!#$%&⋆+./<=>?@^~:*-» кроме «...» или начинается и заканчивается на «^». Примеры операторов: +, -, ^пара^. Если оператор начинается и закачничвается на «^», то он вызывает функцию по имени между «^» со своими аргументами. Например, (2 ^пара^ 3) то же самое, что (пара 2 3).
> список 1 2 3 4 список 5 6 7 '(1 2 3 (5 6) 7)
После любого элемента строки можно следующие элементы писать по одному на строке. Отступ этих элементов должен быть больше отступа текущей строки и одинаков. Если элемент состоит из одного слова, он является занчением, если же из нескольких, то командой, результат которой будет значением элемента.
> список 1 2 3 4 список(5 6) 7 '(1 2 3 (5 6) 7)
> список 1 2 3 4 (список 5 6) 7 '(1 2 3 (5 6) 7)
Если строка очень длинная, то можно перед переносом вставить символ «\», тогда перенос не будет нести синтаксического смысла.
Выбор способа написания определяется удобством чтения. При вводе в окно интерпретатора ввод заканчивает после пустой строки, так как до этого возможно продолжение команды.
2.3 Основы определений
<идентификатор> = <выражение>
> часть = 3 > кусок строка = подстрока строка 0 часть > часть 3
> кусок "три символа" "три"
На самом деле, определение функции также как и определение не функции всего лишь связывает идентификатор с значением и этот идентификатор можно тоже использовать как выражение.
> кусок #<функция:кусок>
> подстрока #<функция:подстрока>
3 Справочник
3.1 Определения
синтаксис
(идентификатор = выражение)
(значения идентификатор ... = выражение) (заголовок(параметры) = команда ... выражение)
заголовок = идентификатор | (заголовок параметры) параметры = параметр ... | параметр ... . параметр-оставшихся параметр = идентификатор | [идентификатор выражение] | ключ идентификатор | [ключ идентификатор выражение]
3.2 Логические выражения
функция
(логический? параметр) → логический?
параметр : любой
3.3 Списки
функция
(список? параметр) → логический?
параметр : любой
функция
(пара? параметр) → логический?
параметр : любой
3.4 Строки
функция
(подстрока строка начало [конец]) → строка?
строка : строка? начало : целое-неотрицательное? конец : целое-неотрицательное? = (длина-строки строка)