Про Lisp-подобные языки говорят, что у этих языков нет синтаксиса. Синтаксис у них, конечно, есть, но максимально примитивный, фактически состоящий из списков и значений. Кроме того, в лиспах отсутствуют ключевые слова и соответствующие им конструкции. В обычных языках существует множество управляющих конструкций, таких как условия, циклы, возврат, присвоение переменных и многие другие. В лиспоподобных языках таких конструкций нет. (Это не значит, что на Racket нельзя реализовать цикл или написать условие — можно!)
Каким же образом Racket понимает, с чем сейчас он работает и что нужно делать? Все дело в формах. Любая корректная программа на Lisp называется формой. Например:
; форма
(displayln "i am from form")
; форма
(+ 1 2)
; и это формы
8
"hello"
; а это не форма, так как такой код завершится с ошибкой
(1 2 3)
Форм всего две — нормальная и составная. Нормальной соответствуют все значения (и определения, с которыми мы познакомимся позже), так как они вычисляются сами в себя, например число 8 или строка "hello". Составная форма — это список, который нужно обработать тем или иным способом (вычислить).
Когда код представлен как список, появляется простор для интерпретации. Возьмём сложение двух чисел, например 3 и 2. В виде списка такое сложение можно представить тремя разными способами:
(3 + 2)
(3 2 +)
(+ 3 2)
В Lisp-языках используется префиксная нотация, то есть первый элемент формы определяет поведение (семантику). Такой способ обладает рядом преимуществ. Например, он позволяет естественным образом выполнять действие с любым набором элементов:
; 3 + 2 + 8 + 3 + 9
(+ 3 2 8 3 9) ; 25
; 3 - 2 - 8 - 3 - 9
(- 3 2 8 3 9) ; -19
Другое преимущество — простота реализации динамической диспетчеризации по сравнению с другими языками. Этому способствуют и макросы.
Выведите на экран значение выражения 10 - 100 - 12 - 18
.
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1#lang racket
2
3(require "../../../src/tests.rkt")
4
5(assert-output "-120")
6
Решение учителя откроется через: