обработать( N) :-
С is N * N * N,
write( С),
куб.
Это был пример программы, декларативный смысл которой трудно сформулировать. В то же время ее процедурный смысл совершенно ясен: чтобы вычислить куб, сначала нужно считать X, а затем его обработать; если Х = стоп, то все сделано, иначе вывести Х3 и рекурсивно запустить процедуру куб для обработки остальных чисел.
С помощью этой новой процедуры таблица кубов чисел может быть получена таким образом:
?- куб.
2.
8
5.
125
12.
1728
стоп.
yes
Числа 2, 5 и 12 были введены пользователем с терминала, остальные числа были выведены программой. Заметьте, что после каждого числа, введенного пользователем, должна стоять точка, которая сигнализирует о конце терма.
Может показаться, что приведённую процедуру куб можно упростить. Однако следующая попытка такого упрощения является ошибочной:
куб :-
read( стоп), !.
куб :-
read( N),
С is N * N * N,
write( С),
куб.
Причина, по которой эта процедура работает неправильно, станет очевидной, если проследить, какие действия она выполняет с входным аргументом, скажем с числом 5. Цель read( стоп) потерпит неудачу при чтении этого числа, и оно будет потеряно навсегда. Следующая цель read введет следующий терм. С другой стороны может случиться, что сигнал стоп будет считан целью read( N), что приведет к попытке перемножить нечисловую информацию.
Процедура куб ведет диалог между пользователем и программой. В таких случаях обычно желательно, чтобы программа перед тем, как читать с терминала новые данные, дала сигнал пользователю о том, что она готова к приему информации, а также, возможно, и о том, какого вида информация ожидается. Это делается обычно путем выдачи 'приглашения' перед чтением. Нашу процедуру куб можно для этого изменить, например, так:
куб :-
write( 'Следующее число, пожалуйста:'),
read( X),
обработать( X).
о6работать( стоп) :- !.
обработать( N) :-
С is N * N * N,
write( 'Куб'), write( N), write( 'равен').
write( С), nl,
куб.
Разговор с новой версией мог бы быть, например, таким:
?- куб.