Внутренняя база данных
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 сек).