20.2 Цикл взаимодействия с пользователем

С Lisp’ом можно работать через специальный цикл вида «read-eval-print и сначала». Изменять состояние Lisp системы можно вызовом в этом цикле действий, имеющих побочные эффекты.

Точное определение такого цикла для Common Lisp’а не указывается здесь специально, оставляя разработчикам поле для творчества. Например, они могут сделать командную строку, или простой текстовый редактор, или сложный графический интерфейс. Разработчики могут предоставлять явный запрос ввода, или (как в MacLisp’е) не загромождать экран подсказками.

Цикл взаимодействия с пользователем должен ловить все исключения и изящно их обрабатывать. Он должен также выводить все результаты вычисления форм, возможно в отдельных строках. Если форма вернула ноль значений, это также должно быть отображено.

Для удобства работы, например в случае, если пользователь забыл сохранить интересное введённое выражение или выведенное значение

Следующие переменные управляются циклом взаимодействия с пользователем,. (Следует отметить, что имена некоторых этих переменных нарушают нотацию глобальных переменных в использовании звёздочек в начале и конце имени.) Эти переменные в основном используются для взаимодействия с пользователем, поэтому имеют короткие имена. Использование этих переменных в программах следует избегать.

[Переменная] +
[Переменная] ++
[Переменная] +++

Когда форма вычисляется в цикле взаимодействия, переменная + связывается с предыдущим прочитанным выражением. Переменная ++ хранит предыдущее относительно значения + (то есть, форма вычисленная два шага назад), и +++ хранит предыдущее значение относительно ++.


[Переменная] -

Когда формы выполняется в цикле взаимодействия, переменная - связана с этой формой. Это значение, которое получит переменная + на следующей итерации цикла.


[Переменная] *
[Переменная] **
[Переменная] ***

Во время вычисления формы в цикле взаимодействия, переменная * связана с результатом выполнения предыдущей формы, то есть значения формы, которая хранится в +. Если результат той формы содержал несколько значений, в * будет только первое. Если было возвращено ноль значений, * будет содержать nil. Переменная ** хранит предыдущее значение относительно *. То есть, результат вычисления формы из **. *** хранит предыдущее значение относительно ***.

Если выполнение + было по каким-то причинам прервано, тогда значения *, ** и *** не меняются. Они изменяются, если вывод значений как минимум начался (необязательно, чтобы он закончился).


[Переменная] /
[Переменная] //
[Переменная] ///

Во время вычисления формы в цикле взаимодействия, переменная / связана со списком результатов выведенных на предыдущей итерации. То есть это список всех значений выполнения формы +. Значение * должно всегда совпадать со значением car элемента значения /. Переменная // хранит предыдущий список значений относительно / (то есть, результат вычисленный две итерации назад), и /// содержит предыдущий список значений относительно ///. Таким образом, значение ** должно всегда совпадать со значением car элемента списка //, а *** с с car элементом ///.

Если выполнение + было по каким-то причинам прервано, тогда значения /, // и /// не меняются. Они изменяются, если вывод значений как минимум начался (необязательно, чтобы он закончился).


В качестве примера работы с этими переменным, рассмотрим следующую возможную работу с системой, где > приглашение ввода:

>(cons - -) ;Итерация 1
((CONS - -) CONS - -) ;Очаровашка?

>(values) ;Итерация 2
                                ;Ничего не выводится
>(cons ’a ’b) ;Итерация 3
(A . B) ;Это одно значение

>(hairy-loop)̂G ;Итерация 4
### QUIT to top level. ;(Пользователь прервал вычисления.)

>(floor 13 4) ;Итерация 5
3 ;Вернулось два значения
1

В этой точке мы имеем:

+++  (cons ’a ’b) ***  NIL ///  ()
++  (hairy-loop)  **  (A . B)//  ((A . B))
+  (floor 13 4)  *  3 /  (3 1)