Работа с последовательностями в ленивом интерпретаторе
Пабло Э. Фект, бывший программист на языке C, беспокоится, что ленивый интерпретатор не вынуждает выражения в последовательности, и оттого некоторые побочные эффекты могут никогда не произойти. Поскольку ни у одного выражения в последовательности, помимо конечного, значение не используется (выражение стоит там только ради своего эффекта, например, чтобы присвоить значение переменной или что-нибудь напечатать), у значения такого выражения не может впоследствии быть применения, для которого его потребуется вынудить (например, в качестве аргумента элементарной процедуры). Поэтому П.Э. Фект считает, что при выполнении последовательности нужно все выражения, кроме последнего, вынуждать. Он предлагает изменить
eval-sequence
из раздела 4.1.1 так, чтобы она использовала
actual-value
вместо
eval
:
(define (eval-sequence exps env)
(cond ((last-exp? exps) (eval (first-exp exps) env))
(else (actual-value (first-exp exps) env)
(eval-sequence (rest-exps exps) env))))
а. Бен Битобор считает, что Пабло неправ. Он показывает ему процедуру
for-each
из упражнения
2.23
— важный пример последовательности с побочными эффектами:
(define (for-each proc items)
(if (null? items)
'done
(begin (proc (car items))
(for-each proc (cdr items)))))
Он утверждает, что интерпретатор из текста (с исходным
eval-sequence
) правильно работает с этой процедурой:
;;; L-Eval input:
(for-each (lambda (x) (newline) (display x))
(list 57 321 88))
57
321
88
;;; L-Eval value:
done
Объясните, почему Бен прав насчет поведения
for-each
.
б. Пабло соглашается с Беном по поводу примера с
for-each
, но говорит, что, предлагая изменить
eval-sequence
, он имел в виду другой тип программ. Он определяет в ленивом интерпретаторе следующие две процедуры:
(define (p1 x)
(set! x (cons x '(2)))
x)
(define (p2 x)
(define (p e)
e
x)
(p (set! x (cons x '(2)))))
Какие значения вернут
(p1 1)
и
(p2 1)
с исходной
eval-sequence
? Каковы будут значения с изменением, которое предлагает Пабло?
в. Пабло указывает также, что изменение
eval-sequence
, которое он предлагает, не влияет на поведение примера из части a. Объясните, почему это так.
г. Как, по-Вашему, нужно работать с последовательностями в ленивом интерпретаторе? Что Вам нравится больше: подход Пабло, подход, приведенный в тексте, или что-нибудь третье?
Комментарии отсутствуют.