Пролог: Как читать данные из консоли и сохранять в базе данных.Получение ошибок - PullRequest
0 голосов
/ 30 января 2019
update :-
    write("Name?:"),
    read(Name),
    assert(Name),nl,
    write("Age?:"),
    read(Age),
    assert(Age),
    write("Continue(y or n)?:"),
    read(Respond),
    process(Respond).

process(y) :-
     write('Name?:'),
     read(Name),
     assert(Name),nl,
     write("Age?:"),
     read(Age),
     assert(Age),
     repeat,
     write("y or n"),
     read(Respond),
     process(Respond).

 process(n) :- !.

Я хочу запустить этот Пролог, чтобы утверждать имя и возраст, но когда я пишу возраст для числа, он показывает

?- update.
Name?:fred.

Age?:|: 25.

ERROR: Type error: `callable' expected, found `25' (an integer)
ERROR: In:
ERROR:    [9] assert(25)
ERROR:    [8] update at c:/example.pl:11
ERROR:    [7] <user>
?- 

Как решить эту проблему.

Ответы [ 3 ]

0 голосов
/ 30 января 2019

Проблема 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

Конкурирующие пути или повторы.

Код использует дваспособы:

  1. Использование повтор / 0
  2. Это рекурсивный , например,

    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.

0 голосов
/ 31 января 2019

Я бы написал несколько помощников:

read_assert(P,V) :- format('~w ? ',[P]), read(V), A =.. [P,V], assert(A).

?- maplist(read_assert, [name,age], Vs).
name ? capellic.
age ? 99.

Vs = [capellic, 99].

?- name(N).
N = capellic.
0 голосов
/ 30 января 2019

Это потому, что assert не работает с переменными.Это утверждает факт или правило;другими словами, assert(something) утверждает, что something должно быть истинным.

Из документации SWI-Prolog :

Утверждение предложения (факт илиправило) в базу данных.

Целочисленное значение не является правилом или фактом.Это (в данном случае) целое число, а не то, что оценивается как логическое значение.Нет смысла утверждать значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...