Песочница

Значения, имена и процедуры

Научитесь читать литералы и вызовы Лиспекса, связывать имена через define и let и создавать повторно используемые процедуры через lambda.

На первом шаге вы запустили целую программу. Теперь мы разберём её на те несколько форм, из которых она собрана. Сначала стоит развести три вещи. Есть само значение, есть имя, которое на это значение указывает, и есть вызов процедуры, который значение вычисляет. Когда эти три вещи различаются, скобки читаются в устойчивом порядке.

Значения могут стоять сами

Числа, булевы значения, строки, знаки и цитированные данные являются значениями.

LISPEX
42
#t
"Lispex"
#\L
'ready

Чтобы записать одиночный знак как значение, поставьте перед ним #\. Запись #\L выше это одна заглавная L. Это значение другого рода, чем строка в двойных кавычках.

Символ-идентификатор ready без кавычки ведёт себя иначе. В таком виде Лиспекс принимает ready за имя и ищет его значение. А запись 'ready сохраняет этот символ как данные.

Список в позиции вызова просит выполнить работу

Это выражение можно прочитать, начав с самого внутреннего вызова и двигаясь наружу.

LISPEX
(+ 10 (* 2 3))

Сначала Лиспекс находит +, затем вычисляет 10, а потом слева направо вычисляет (* 2 3). Внутренний вызов даёт 6, поэтому внешний вызов становится равносилен (+ 10 6).

Результат

OUTPUT
16

Не всякие скобки означают обычный вызов. define, lambda, let и if управляют тем, какие части выражения вычисляются и где видны имена.

Свяжите значение с именем

define создаёт или обновляет верхнеуровневое связывание, то есть имя, которым может пользоваться остальной файл.

LISPEX
(define fee 3)
(+ 20 fee)

Результат

OUTPUT
23

Само определение ничего не печатает. Последнее сложение печатает одно значение.

Когда имя нужно только внутри одного тела, возьмите let.

LISPEX
(let ((base 7))
  (* base 2))

Результат

OUTPUT
14

Связывание base видно только внутри тела и исчезает за его пределами. Такая узкая область видимости делает временное вычисление понятнее.

Создайте повторно используемую процедуру

Сокращённая запись определения позволяет сразу назвать и саму процедуру, и её входы.

LISPEX
(define (price-with-fee price fee)
  (+ price fee))

(price-with-fee 20 3)

Результат

OUTPUT
23

Если записать то же самое в длинной форме, станет видно, что процедура сама является значением.

LISPEX
(define price-with-fee
  (lambda (price fee)
    (+ price fee)))

Процедура проверяет, сколько аргументов ей передали. Вызов price-with-fee с одним или тремя аргументами приведёт к ошибке выполнения, а не к неявному значению по умолчанию.

Соедините части

LISPEX
(define (price-with-fee price fee)
  (+ price fee))

(list (price-with-fee 20 3)
      (let ((base 7))
        (* base 2)))

Результат

OUTPUT
(23 14)

Обратите внимание на порядок. Сначала вычисляется первый элемент списка, затем второй. list получает эти два готовых значения и создаёт (23 14).

Упражнение

Определите процедуру triple, которая умножает свой вход на 3, и вызовите её дважды внутри list, чтобы получить (12 21).

Показать один ответ
LISPEX
(define (triple n)
  (* n 3))

(list (triple 4) (triple 7))

Готовы к шагу 3?

Переходите дальше, когда сможете объяснить, почему цитированный символ-идентификатор остаётся данными, почему (* 2 3) вычисляется до того, как внешнее сложение им воспользуется, и где видно имя из let. Дальше идёт Код и есть данные.