Проблема 1
Неправильный ввод для assert / 1
Проблема не только в Age
, а в любом входе, который использует assert
, например
?- update.
Name?:Fred
|: .
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] assert(_4940)
ERROR: [8] update at c:/example.pl:8
ERROR: [7] <user>
?- update.
Name?:Jim.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] assert(_5826)
ERROR: [8] update at c:/example.pl:8
ERROR: [7] <user>
Проблема в том, что assert / 1 не дан факт или правило.
assert/1
говорит:
Включение предложения (факта или правила) в базу данных.
См. факты и правила
В примеревыше Fred
не факт, потому что он не заканчивается точкой (.
).
В приведенном выше примере с Jim.
был указан период, но поскольку Jim
начинается с заглавной буквы, это не факт или правило, а переменная.
Когда возраствводится как число, опять же, это не факт или правило, это целое число.
Задача 2
Использование read / 1 , которое гласит:
Считать следующий термин Prolog из текущего входного потока и объединить его с Term.
При чтении Prolog term вход должен заканчиваться точкой.
Это не только требует, чтобы ввод был термином, но и заканчивался .
, что еще более запутанно, учитывая подсказку, например, Age
.Большинство примеров, которые вы найдете, делают то, что вы сделали, исправленный код ниже делает то, что вы хотите.
Задача 3
Конкурирующие пути или повторы.
Код использует дваспособы:
- Использование повтор / 0
Это рекурсивный , например,
process(y) :-
...
process(Respond).
Это затрудняет работу кода.
Задача 4
Дублирующийся код, например
write("Name?:"),
read(Name),
assert(Name),nl,
write("Age?:"),
read(Age),
assert(Age),
write("Continue(y or n)?:"),
read(Respond),
process(Respond).
Дублированный код более вероятенпривести к проблемам, когда одна копия исправлена, а другая не исправлена.
Исправление задачи 1
Перед вводом в факт вводите факт с помощью assert/1
, например,
Значения в переменных
Name
Age
Переменные, преобразованные в факты, добавив функтор
name(Name)
age(Age)
Факты, используемые с assert/1
assert(name(Name))
assert(age(Age))
Исправление задачи 2
Используйте read_string / 5 , например,
read_string(user, "\n", "\r", End, Name)
Это считывает ввод в переменную Name
как строку.Теперь, когда входные данные являются строкой, а не термином Пролог, период больше не требуется.Существуют предикаты, которые работают со строками .
Исправление проблемы 3
Используйте форму рекурсии и удалите repeat / 0 .
Это можеттакже используйте repeat/0
вместо рекурсии.Исправленный код ниже использует рекурсию для демонстрации изменения на process/1
.
Исправление проблемы 4
Просто рефакторинг кода.Вы можете увидеть это в исправленном коде в конце.
Теперь с исправлениями на месте.
Изменить 1
Поскольку ввод для continue
больше не термин, например y
или n
, но строка, параметр для process
должен быть строкой, например
process("y") :-
process("n") :-
Изменить 2
Возраст будетбыть утвержденным как строка, но лучше было бы заявить как целое число.
number_string / 2 может решить эту проблему, например,
number_string(Age_n,Age),
assert(age(Age_n))
Изменить 3
user27815 Отвечая на вопрос в комментарии:
Вам нужен процесс обработки ("n"): -!.?
Поскольку
process(Respond).
не создает точку выбора, вырезать не нужно.
Исправленный код:
update :-
% Respond will be read as a string and not as a term, so it needs "".
process("y").
process("y") :-
write('Name: '),
read_string(user, "\n", "\r", End, Name),
assert(name(Name)),
write("Age: "),
read_string(user, "\n", "\r", End, Age),
number_string(Age_n,Age),
assert(age(Age_n)),
write("Continue: (y or n) "),
read_string(user, "\n", "\r", End, Respond),
process(Respond).
process("n").
Пример выполнения:
?- update.
Name: Fred
Age: 30
Continue: (y or n) y
Name: Jim
Age: 21
Continue: (y or n) n
true.
Чтобы проверить, обновлена ли база данных, используйте перечисление / 1
?- listing(name/1).
:- dynamic name/1.
name("Fred").
name("Jim").
true.
?- listing(age/1).
:- dynamic age/1.
age(30).
age(21).
true.
Бесплатное улучшение.
Хранение фактов имени и возраста отдельно не сохраняет связь между ними.Лучшим решением будет факт person
с обоими значениями Name
и Age
.
Вот необходимый модифицированный код.
update :-
% Respond will be read as a string and not as a term, so it needs "".
process("y").
process("y") :-
write('Name: '),
read_string(user, "\n", "\r", End, Name),
write("Age: "),
read_string(user, "\n", "\r", End, Age),
number_string(Age_n,Age),
assert(person(Name,Age_n)),
write("Continue: (y or n) "),
read_string(user, "\n", "\r", End, Respond),
process(Respond).
process("n").
Пример выполнения:
?- update.
Name: Fred
Age: 30
Continue: (y or n) y
Name: Jim
Age: 21
Continue: (y or n) n
true.
Чтобы убедиться, что база данных была обновлена, используйте список / 1
?- listing(person/2).
:- dynamic person/2.
person("Fred", 30).
person("Jim", 21).
true.
После того, как вы заметили свой удаленный ответ.
В вашем удаленном ответе у вас есть
?- person(name(N), age(A)).
N = nancy,
A = 22;
N= steve,
A = 100;
true.
Для этого варианта факта, который нужно создать, необходимо изменить
assert(person(name(Name),age(Age_n)))
, однако это может быть не самым оптимальным способом.,
В Прологе позиции обычно указывают значение значения, например, первая позиция name
, а вторая позиция age
.В этом варианте, добавляя функторы name
и age
к факту person/2
, вы дублируете известные знания, но, что более важно, вероятность того, что Prolog должен выполнить.
Например:
Если факт был person(Name,Age).
, чтобы получить Name
и Age
Прологу требуется только одно объединение.Но с person(Name,Age).
Прологу теперь нужно объединиться с person(name(nancy),age(22))
, чтобы получить Name
, снова объединиться с name(nancy)
и получить Age
, должно объединиться с age(22)
.Вы также можете использовать person(name(Name),age(Age)).
, который требует только одного объединения, но теперь делает ваш код более многословным.
При первом изучении Пролога этот костыль помогает, но при работе с большими наборами данных это начинает влиять на производительность.
Еще одним примечанием в вашем удаленном ответе является то, что имена людейвсе еще основан на использовании read/1
, например nancy
и steve
.Хотя многие примеры Пролога делают это, нет необходимости сохранять их как таковые, они могут быть строками.Скорее всего, код никогда не должен будет точно совпадать с nancy
или steve
и вместо этого всегда будет ссылаться на них как на значение в переменной.Хорошая особенность сохранения их в виде строк состоит в том, что при их записи они будут правильно отображаться как Nancy
и Steve
.