Песочница

Выражения и порядок вычисления

Предсказывайте изменения значений, вывод и ошибки, следуя порядку вызовов процедур и условных выражений.

Вы можете предсказать результат программы, проследив порядок изменения значений и вызовов процедур. Лиспекс сначала вычисляет оператор вызова, затем операнды слева направо.

Проследите изменение значения

Вставьте эту программу целиком в песочницу.

LISPEX
(define x 0)
(list (begin (set! x 1) x) (begin (set! x (+ x 1)) x))

Результат

ВЫВОД
(1 2)

Первый begin меняет x на 1 и возвращает 1. Второй читает новое значение, прибавляет единицу, сохраняет 2 и возвращает его. Процедура list получает сначала 1, затем 2.

Оператор вызова — это выражение, которое даёт процедуру. Здесь это list. Операнды дают значения аргументов, здесь это два выражения begin.

Учитывайте вид выражения

ВыражениеПорядок вычисленияЧто происходит с результатами
вызов процедурыоператор, затем операнды слева направопосле проверки числа аргументов вызывается процедура
begin или тело процедурывыражения слева направоранние результаты отбрасываются, последний возвращается
ifусловие, затем выбранная ветвьвозвращается результат этой ветви
andоперанды слева направоостановка на #f либо возврат последнего результата
orоперанды слева направоостановка на первом результате, отличном от #f
letинициализаторы слева направо, с именами из внешней областиновые имена связываются со значениями для тела
let*инициализатор, затем связывание имениследующие инициализаторы видят предыдущие новые имена
letrecсначала память для всех имён, затем вычисление и запись начальных значений слева направовсе имена видны при инициализации

Инициализатор задаёт начальное значение имени. Область видимости определяет, где доступно имя. Место хранения одного связанного значения называется ячейкой. Чтение ячейки letrec до присвоения ей значения даёт E321.

Ошибка останавливает текущее вычисление. Указанный порядок относится к выражениям, до которых программа успела дойти. Выражения перед последним в begin или теле могут возвращать любое число значений, поскольку их результаты отбрасываются.

Посмотрите, что будет пропущено

Запустите этот пример как отдельную программу.

LISPEX
(list (if #t 7 (/ 1 0))
      (and #f (/ 1 0))
      (or 0 (/ 1 0)))

Результат

ВЫВОД
(7 #f 0)

Ни одно деление не выполняется. if выбирает 7, and останавливается на #f, а or — на 0. Ложным считается только #f, поэтому 0 считается истинным.

Число аргументов проверяется после вычисления

Ошибка числа аргументов не мешает сначала вычислить оператор и операнды. После установки Native CLI сохраните этот полный пример в arity-effects.lspx.

LISPEX
((begin (display "operator ") (lambda (x) x))
 (begin (display "left ") 1)
 (begin (display "right") 2))
SH
lispex run arity-effects.lspx

Стандартный вывод содержит этот текст без перевода строки в конце:

operator left right

Процедура ожидает один аргумент, но получает два. Затем команда пишет в стандартный поток ошибок:

E302 arity-effects.lspx:1:1 arity mismatch: expected 1 argument(s), got 2

Код завершения — 1, новые файлы не создаются. Тело процедуры не выполняется.

Различия форм let описаны в главе «Связывания и область видимости». Правила выбора ветви приведены в главе «Условия».