Результат. Объяснить, почему программа на этом языке состоит из тех же списков, которыми она управляет, и почему это полезно, а не просто любопытный факт.
Что нужно знать сначала. Чтение скобок. Больше ничего.
Одна и та же форма означает две вещи
Эту форму вы уже знаете.
(+ 2 3)Если её выполнить, получится пять. Теперь поставьте перед ней апостроф.
'(+ 2 3)Получится список из трёх элементов, символ +, число два и число три. Ничего
не сложилось и не вычислилось. Апостроф говорит воспринимать эту запись как
данные, а не как команду к исполнению.
Один и тот же текст становится вызовом или списком исключительно в зависимости от того, просите ли вы его выполнить. В большинстве языков вызов функции и список из трёх элементов остаются несвязанными понятиями, которые просто используют одинаковые знаки препинания. Здесь это одна вещь, показанная с двух сторон.
Почему это важно в обычном коде
Чтобы оценить выгоду этого подхода, не нужно писать компилятор. Польза проявляется в первый же раз, когда программа возвращает решение вместо числа.
Допустим, под именем answer лежит список из двух элементов. Достать значения
из списка позволяют два имени. car возвращает первый элемент, а cdr
возвращает всё, что идёт после первого, тоже списком. Ни одно из этих имён ни о
чём не говорит, потому что оба взяты прямо из названий регистров той машины, на
которой лисп заработал впервые. Не пытайтесь их расшифровать. Просто запомните
оба.
(define answer '(decision allow))
(car (cdr answer))cdr отдаёт список из одного элемента (allow), а car достаёт оттуда сам
элемент, поэтому в результате получается allow. Программа составила небольшой
фрагмент структурированных данных той же самой записью, которой написана сама,
и обычными операциями со списками достала из него нужную часть. Не потребовался
ни отдельный синтаксис для литералов, ни особый формат для конвертации данных
перед сохранением или отправкой, ни объектная модель, которую нужно описывать
заранее.
Так выглядит эта идея в повседневных задачах. Программа, создающая структуру, производит то же самое, из чего сделана сама, поэтому инструменты для одного работают и для другого.
Цитирование и его семейство
У цитирования есть родственники, с которыми вы встретитесь позже. Четыре знака ниже являются обозначениями, поэтому их стоит прочитать, а не запускать.
'x
`x
,x
,@xsПервый знак называется цитированием, quote, и означает «считать данными».
Второй называется квазицитированием, quasiquote, и означает «считать данными,
но разрешить пропуски». Третий это unquote, он заполняет пропуск вычисленным
значением, а четвёртый это unquote-splicing, он вставляет на место пропуска
список. Они нужны для того, чтобы программа могла
строить структуру, большая часть которой фиксирована, а отдельные части
подставляются.
Сейчас они вам не нужны. Достаточно знать об их существовании, чтобы не удивляться обратному апострофу, когда он окажется не строкой.
Честная оговорка
Самое знаменитое следствие принципа равенства кода и данных заключается в том, что программы могут писать программы. Это правда, и одновременно это не то, чем занимается большинство рабочего кода. Большинство рабочего кода выигрывает скромнее, как показано выше, за счёт единой записи и одного набора инструментов.
Относитесь к этой грандиозной идее как к открытой двери, а не как к комнате, в которую обязательно нужно войти.
Попробуйте сами
Предскажите оба результата до запуска.
(list (+ 1 2) '(+ 1 2))Показать ответ
(3 (+ 1 2)). Первый элемент вычислился и стал тройкой. Второй был
процитирован, поэтому остался списком из трёх элементов. Один и тот же текст
даёт два исхода, и всё решает единственный апостроф.
Готовы двигаться дальше?
Вы умеете объяснить, что делает апостроф, и привести пример программы, возвращающей структурированные данные. Вы также можете пояснить, почему единая форма записи для данных и вызовов удобна, а не запутывает.
Переходите к разделу Данные, условия и решения, где именно из этих деталей строятся настоящие правила.