Внутренняя база данных
4.3. Цикл foreach
Цикл foreach, также как и предыдущий цикл, не может использоваться без точек возврата. Он имеет вид:
foreach <действие с возвратом> do <процедура> end foreach.
Например:
run():-
foreach женщина(X) do
write(X), nl
end foreach,
_ = readLine().
Циклы fail и foreach завершаются, когда не остается точек возврата.
В приведенной ниже программе в цикле fail выводятся сведения обо всех произведениях, а в цикле foreach — только об авторах произведений, которые хранятся в четных по номеру записях.
class facts
book: (integer Номер, symbol Автор, symbol Название).
clauses
book(1, "Толстой", "Война и мир").
book(2, "Чехов", "Вишневый сад").
book(3, "Пушкин", "Евгений Онегин").
book(4, "Достоевский", "Преступление и наказание").
run():-
write("Авторы и их произведения\n\n"),
book (_, Author, Title),
write(Author, " - ", Title), nl,
fail;
nl, % вывод авторов книг из четных по номеру записей
foreach book(N, Author, _), N mod 2 = 0 do
write(Author), nl
end foreach,
_ = readLine().
Пример
4,1.
"Книги"
Упражнение 1. Организуйте в программе "Книги" (см. листинг 4.1) такой цикл, чтобы он прекращался по достижении книги с номером 3.
4.4. Цикл repeat
В отличие от двух предыдущих видов циклов цикл repeat может использоваться и тогда, когда в повторяемом действии есть откат, и тогда, когда его нет. Он устроен следующим образом:
repeat() <действие> <условие выхода из цикла>.
Определение предиката repeat имеет вид:
class predicates
repeat: () multi.
clauses
repeat().
repeat():-
repeat().
Этот предикат ничего не делает, кроме того, что ставит точки возврата, потенциально бесконечное число раз. Условие выхода из цикла должно быть истинным только в момент самого выхода. В остальное время оно вызывает откат. Если в разделе <действие> нет точек возврата, то откат идет к предикату repeat.
Рассмотрим цикл:
печать():-
С = varM::new(0), % счетчик
repeat(),
C:value := C:value + 1, % увеличение счетчика на 1
nl, % переход на новую строку
foreach женщина(X) do % печать имен женщин
write(X, "\t")
end foreach,
C:value = 3, % условие выхода из цикла
!.
печать().
Объект класса varM хранит изменяемое значение value. В этом цикле выполняется троекратный вывод на печать имен всех женщин:
Мария Анна Мария Анна Мария Анна
В следующей программе приводится пример repeat-цикла, который используется для вывода символов из буфера ввода [2, 18]. После запуска программы нужно ввести какой-либо текст (слово) и нажать клавишу Enter. После этого текст будет выведен посимвольно, с небольшой паузой перед выводом каждого символа. Символы преобразуются в верхний регистр.
clauses % наберите слово, нажмите Enter
run():-
std::repeat(),
Char = readChar(), % считывание символа из буфера ввода
UpperCaseChar = string::charUpper(Char),
programControl::sleep(500), % 1000 = 1 сек
write(UpperCaseChar),
Char = '\n', % условие выхода из цикла
!,
clearInput(), % очищает буфер ввода
_ = readLine();
succeed().
Пример
4.2.
"Буквы"
Предикат readChar считывает символ (char) из буфера ввода. В отличие от предиката readLine он не очищает буфер ввода. Символы домена char заключаются в одинарные кавычки. Предикат charUpper переводит символ в верхний регистр. Предикат sleep прерывает исполнение программы на заданное время, которое указывается в миллисекундах (1000 миллисек = 1 сек).