1. Предикат read/1.
В отличие от предиката write, который всегда успешно согласуется, встроенный предикат read(Term) определен так, что он не только дает возможность ввести с клавиатуры некоторый терм, но и проверяет, унифицируется ли заданный аргумент Term с введенным термом.
Попытка пользователя ввести выражение, не являющееся термом, приведет к ошибке.
Замечание
Ввод терма всегда должен заканчиваться точкой и нажатием клавиши Enter.
Если аргументом read является переменная, то унификация будет успешной и эта переменная будет конкретизирована введенным с клавиатуры значением.
1)?- read(X). abc. /*Введен атом */ X = abc Yes | 2)?- read(X). t(1,2). /* Введен составной терм */ X = t(1,2) Yes |
3)?- read(X). $asdf$. /*Введена строка */ X = $asdf$ Yes | 4)?- read(t(X,Z)). t(Y,2). /* Унификация t(X,Z)=t(Y,2)*/ X = H1 /* H1 – внутреннее имя Y */ Z = 2 Yes |
5)?- read(5). 5. Yes | 6)?- read('Терм'). Тер. No |
2. Предикат read_string/1
Для ввода символьных строк удобнее использовать предикат read_string(String), который при конкретизированном аргументе, как и read, выполняет сверку заданной и введенной строк. Отличий два: (1) ввод не нужно завершать точкой, только нажать Enter, (2) вводимую строку не нужно заключать в знаки доллара (см. выше пример 3).
Примеры.
7)?- read_string(X). Строка X = $Строка$ yes | 8)?- read_string(X). t(1,2) X = $t(1,2)$ /*Преобразовано в строку */ Yes |
9)?-read_string($Строка$). Строка /*Введена строка */ Yes | 10)?- read_string('Строка'). /* атом! */ Строка /*Введена строка */ Yes |
Различие между предикатами read и read_string принципиальное. С помощью read можно прочесть составной терм и тут же использовать его как цель, а read_string превращает всё в строки (см. пример 8), которые целью быть не могут.
Например, предположим, что в программе имеется факт t(2,3). Напишем вопрос, где предполагается ввод составного терма (как элемента данных) и использование этого терма как цели для согласования.
?- read(X),X.
t(Z,Y). /* Вводим составной терм */
X = t(2,3) /* Результат конкретизации X= t(Z,Y)при вводе и
унификации t(X,Y)= t(2,3) с фактом из программы */
yes
ЗАДАНИЕ 2
1. Проверить выполнение примеров, приведенных для предикатов read и read_string.
2. База данных состоит из двух таблиц. Первая хранит общую информацию о студенте, вторая — о его учебе. Таблицы связаны между собой по полю "Номер зачетной книжки".
Задача состоит в том, чтобы сформировать запрос, который по фамилии студента формирует и выводит ответ, включающий информацию сразу из обеих таблиц.
а) В программе описать информацию из таблиц с помощью двух предикатов, например, person/4 и student/4. Элементы с текстовой информацией в предикатах представлять как строки ($Александрова$, $Мех.‑мат.$ и т.п.).
Таблица 1
Номер зачетной книжки | Фамилия | Инициалы | Год рождения |
Александрова | А.А. | ||
Иванов | И.И. | ||
Петров | П.П. | ||
Сидоров | С.С. |
Таблица 2
Номер зачетной книжки | Факультет | Специальность | Курс |
Мех.-мат. | Информационные технологии | ||
ФВТ | Информационные системы | ||
ФВТ | Системный анализ и управление | ||
Физический | Нанотехнологии |
б) Подготовить в программе правило с заголовком без параметров (по аналогии с заданием 1), в котором формулируется вопрос: сначала предлагается ввести фамилию студента, а затем по этой фамилии находится и выводится вместе сводная информация об этом студенте (пока не вся).
Диалог пользователя с программой должен выглядеть так:
3. Убедиться, что программой выдаются правильные ответы.
4. Программа была составлена в расчете на конкретную задачу: вывод информации об одном студенте. Выясним, нельзя ли, используя ту же программу, получить информацию обо всех студентах сразу. Для этого нужно запустить запрос и вместо конкретной фамилии попытаться ввести какую-нибудь переменную, например, Z. Какой получен ответ?
Предикат string_term
Причина, по которой не удалось использовать переменную для запроса информации обо всех студентах, состоит в том, что введенная переменная была истолкована как строка (т.е. $Z$), потому что для ввода был использован предикат read_string. Чтобы не менять этот предикат, но решить эту проблему, нужно дополнительно выполнить преобразование строки $Z$ в переменную Z.
Взаимные преобразования строк и термов можно выполнять с помощью предиката string_term/2. В качестве первого аргумента предикат ожидают строку, а в качестве второго — терм. Предикат позволяет выполнять преобразование
а) строк в термы:
б) термов в строки:
в) а также выяснять, преобразуются ли друг в друга заданные терм и строка:
Замечание
Помимо этого предиката система имеет также несколько других встроенных предикатов для выполнения преобразований типов данных:
string_atom (String, Atom),
string_integer (String, Integer)
И некоторые другие.
ЗАДАНИЕ 2 (продолжение)
Добавить в программу новую цель: после ввода фамилии преобразовать введенную строку в терм. Это позволяет рассматривать имя переменной, введенное с помощью read_string, как переменную, а не строку.