Lisp/Scheme: Progn vs And

Я хотел бы знать, могу ли я заменить progn на и в ситуациях, когда функция должна вычислять последовательность s-выражений.

Пример взят из How To Design Programs (http://htdp.org/2003-09-26/Book/curriculum-ZH-9.html#node_thm_6.6.12)

"Разработайте функцию draw-and-clear-rectangle, которая рисует прямоугольник, приостанавливается на некоторое время, а затем очищает прямоугольник".

(define (draw-and-clear a-rectangle)
  (and (draw-solid-rect... )
       (sleep-for-a-while... )
       (clear-solid-rect... )))

Поскольку аргументы and оцениваются последовательно, есть ли разница с использованием формы progn/begin?


person Victor Marconi    schedule 11.12.2014    source источник
comment
Большинство версий AND в Лиспе останавливаются, когда одна из подформ возвращает NIL. PROGN всегда будет запускать все подчиненные формы,   -  person Rainer Joswig    schedule 11.12.2014


Ответы (2)


Я не читал HtDP, но думаю, что они используют and вместо begin, потому что некоторые изучаемые языки не предоставляют begin.

В Scheme единственным ложным значением является #f, и, в частности, многие «побочные» процедуры возвращают «неопределенное значение»¹, которое неизменно является истинным значением, поэтому вы можете эффективно упорядочить их, используя and. Это контрастирует с Common Lisp, где процедуры с побочными эффектами обычно возвращают nil, что является ложным значением.

¹ Большинство реализаций Scheme последовательно возвращают одно и то же неопределенное значение: в Racket используется (void), а в большинстве других реализаций, не использующих (void), возвращается (cond).

person Chris Jester-Young    schedule 11.12.2014
comment
Я не думаю, что это верно для Common Lisp. Многие функции с побочными эффектами возвращают какой-то объект... - person Rainer Joswig; 11.12.2014
comment
@Rainer Я не имею в виду функции линейного обновления (например, nreverse), я говорю о таких вещах, как setf, которые используются исключительно для побочных эффектов. - person Chris Jester-Young; 11.12.2014
comment
Это странно. SETF в Common Lisp возвращает несколько значений последней формы... - person Rainer Joswig; 11.12.2014
comment
Упс, надо было иметь перед собой CLHS, прежде чем писать такие комментарии. :-) - person Chris Jester-Young; 11.12.2014
comment
Можно увидеть такой код (let ((obj ...)) ... (foo (setf obj (make-bar :baz 42))) ... obj ...). Это требует, чтобы SETF возвращал что-то полезное... - person Rainer Joswig; 11.12.2014

progn будет последовательно оценивать каждое из своих S-выражений. and не будет оценивать ничего после первого, которое вернет false (#f в Scheme или nil в Common Lisp). Такое поведение называется замыканием логических операторов.

(Точно так же or не будет оценивать S-выражение после первого, возвращающего истинное значение.)

person L33tminion    schedule 11.12.2014