Prolog 序言:如何从控制台读取数据并存储到数据库中。出错

Prolog 序言:如何从控制台读取数据并存储到数据库中。出错,prolog,Prolog,我想运行这个Prolog来断言名称和年龄,但是当我为数字写年龄时,它会显示出来 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) :-

我想运行这个Prolog来断言名称和年龄,但是当我为数字写年龄时,它会显示出来

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) :- !.

如何解决这个问题

这是因为assert对变量不起作用。它主张一个事实或规则;换句话说,断言某事断言某事必须是真实的

从:

将子句事实或规则断言到数据库中

整数值不是规则或事实。在本例中,它是一个整数,而不是计算为布尔值的值。断言一个值没有意义。

问题1

输入不正确

问题不在于年龄,而在于任何使用断言的输入,例如

这使得代码很难工作

问题4

重复代码,例如

process(y) :-
  ...
  process(Respond).
当一个副本被更正而另一个副本未被更正时,重复的代码更可能导致问题

问题1修复

在使用assert/1将输入存储到数据库之前,将其设置为事实,例如

变量中的值

write("Name?:"),
read(Name),
assert(Name),nl,
write("Age?:"),
read(Age),
assert(Age),
write("Continue(y or n)?:"),
read(Respond),
process(Respond).
通过添加

与assert/1一起使用的事实

问题2修复

使用,例如

这会将输入作为字符串读入变量名。既然输入是一个字符串,而不是Prolog术语,就不再需要句点了。有

问题3修复

使用递归形式并删除。 这也可以使用repeat/0而不是递归。下面更正的代码使用递归来演示对process/1的更改

问题4修复

只需重构代码。您可以在最后更正的代码中看到这一点

现在修复到位了

变化1

由于continue的输入不再是一个术语,例如y或n,而是一个字符串,因此process的参数需要是一个字符串,例如

read_string(user, "\n", "\r", End, Name)
变化2

年龄将作为字符串断言,但最好作为整数断言

可以解决这个问题,例如

process("y") :-

process("n") :-
变化3

用户27815在评论中问道:

您需要切入加工吗

如果不创建选择点,则不需要剪切

更正代码:

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 :-
     % 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").
要检查数据库是否已更新,请使用

免费升级

将姓名和年龄这两个事实分开并不能保持它们之间的关系完整。更好的解决方案是同时包含姓名和年龄值的person事实

下面是必要的修改代码

?- listing(name/1).
:- dynamic name/1.

name("Fred").
name("Jim").

true.

?- listing(age/1).
:- dynamic age/1.

age(30).
age(21).

true.
运行示例:

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 :-
     % 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").
要检查数据库是否已更新,请使用

注意到你删除的答案后

在你删除的答案中,你有

?- 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.
然而,这可能不是最佳的方式

在Prolog中,位置通常表示值的含义,例如,第一个位置是名称,第二个位置是年龄。在这个变体中,通过将函子名称和年龄添加到事实person/2,可以复制已知的知识,但更重要的是,Prolog必须完成的工作量

例如:

如果事实是人名,年龄。要了解姓名和年龄,序言只需要一个统一。但是有名字,年龄。Prolog现在需要和人名Nancy,22岁统一,那么要得到名字就必须和人名Nancy重新统一,要得到年龄就必须和22岁统一。您还可以使用personnameName、ageAge。这只需要一个统一,但现在使您的代码更加冗长

当第一次学习Prolog时,这个拐杖会有所帮助,但当使用较大的数据集时,这会开始影响性能


删除答案中的另一项注意事项是,这些人的姓名仍然基于read/1,例如nancy和steve。虽然许多Prolog示例都这样做,但不需要将它们保留为字符串,它们可以是字符串。很可能代码永远不需要与nancy或steve完全匹配,而是始终将它们作为变量中的值引用。将它们保留为字符串的好处是,在将它们写出来时,它们将正确地显示为Nancy和Steve。

我会写一些帮助:

assert(person(name(Name),age(Age_n)))

有什么事吗?是的,我试着用这种方法,效果很好!使用assertupdateN,A,是否需要切入过程N:-?我认为不需要。@user27815不,不需要切割。
?- update.
Name: Fred
Age: 30
Continue: (y or n) y
Name: Jim
Age: 21
Continue: (y or n) n
true.
?- listing(name/1).
:- dynamic name/1.

name("Fred").
name("Jim").

true.

?- listing(age/1).
:- dynamic age/1.

age(30).
age(21).

true.
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.
?- 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)))
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.