欢迎来到 Prolog!我很高兴你试一试,我希望你发现它很好地满足了你的想象,因为你似乎有很多!
你在这里为 Prolog 使用了很多奇怪的术语。我不清楚您所说的“框架”或“节点”或“提取”是什么意思,我很确定您正在以一种不恰当的方式使用“咨询”。我不知道这是因为本教程是为 SICStus 编写的,还是只是通常的混淆。我通常也不会想到在 Prolog 中进行继承,但我认为我确实理解这部分内容。所以我希望你能一起玩,我们会看看我是否能回答你的问题。
第一件事。这没什么大不了的,但平均分数应该这样实现:
avg_score(Z) :-
student(jack, X),
student(jill, Y),
Z is (X + Y) / 2. % <-- note the use of 'is' instead of '='
这是一个常见的初学者错误。Prolog 默认情况下不计算代数,所以当你说(X + Y) / 2
你真正在做的只是构建一个表达式时,与div(plus(X, Y), 2)
. 真正的区别在于,它is
知道如何评估代数表达式,例如(X + Y) / 2
but not div(plus(X, Y), 2)
。clpfd
(我会预先警告您,如果您从头开始使用 Prolog并使用#=
而不是. ,您会发现 Prolog 更有意义is
。)
avg_score
不,当然,没有什么帮助的是它jack
并且jill
嵌入其中。有一天,您可能想要计算所有学生的平均分数。首先让我们计算平均值:
average(L, Average) :-
sum(L, Sum),
length(L, Length),
Average is Sum / Length.
% this is overly complex because I wanted to show you
% the tail recursive version
sum(L, Sum) :- sum(L, 0, Sum).
sum([], Sum, Sum).
sum([X|Xs], Acc, Sum) :- Acc1 is X + Acc, sum(Xs, Acc1, Sum).
现在我们可以这样得到所有学生的平均值:
avg_score(Z) :-
findall(X, student(_, X), Scores),
average(Scores, Z).
我不知道这是否与您的要求有关,但似乎它可能会有所帮助,所以它就在那里。
当然,另一种可能性是将事物参数化。我们可以获取原始代码并由学生对其进行参数化:
avg_score(Student1, Student2, Z) :-
student(Student1, X),
student(Student2, Y),
Z is (X + Y) / 2.
这似乎与查询动物寓言更相关。而不是问attack(X)
你会问attack(fire_warrior, X)
。
当您对 Prolog 如此陌生时,我讨厌将您送到 Logtalk,但我怀疑它可能包含您正在寻找的一些答案。它特别擅长以 vanilla Prolog 可能不具备的方式处理继承。但这可能是一个很大的转移。例如,您可以像这样处理查询攻击状态的继承链:
% this is the inheritance tree
parent_class(character, base).
parent_class(npc, character).
parent_class(enemy, npc).
parent_class(red_faction, enemy).
parent_class(blue_faction, enemy).
parent_class(fire_warrior, red_faction).
parent_class(water_consort, blue_faction).
% these are the attack bonuses
attack_bonus(base, 0).
attack_bonus(red_faction, 1.5).
attack_bonus(blue_faction, 1).
calc_attack_bonus(X, Bonus) :-
attack_bonus(X, Bonus), !.
calc_attack_bonus(X, Bonus) :-
\+ attack_bonus(X, Bonus),
parent_class(X, Parent),
calc_attack_bonus(Parent, Bonus).
这似乎适用于一些基本查询:
?- calc_attack_bonus(fire_warrior, Bonus).
Bonus = 1.5.
?- calc_attack_bonus(character, Bonus).
Bonus = 0.
我不知道你是否想要这种行为:
?- calc_attack_bonus(tree, Bonus).
false.
如果没有,很容易修复(如果parent_class
失败,将 Bonus 统一为 0,否则重复)。
然而,这并不是所有可扩展的。一种更可扩展的方法可能是这样的:
% these are the attack bonuses
attribute(attack_bonus, base, 0).
attribute(attack_bonus, red_faction, 1.5).
attribute(attack_bonus, blue_faction, 1).
% base stats
attribute(base_stat, character, 8.0).
attribute(level, fire_warrior, 1.0).
现在我们可以轻松编写我们需要的规则了:
calc_attribute(X, Attribute, Value) :-
attribute(X, Attribute, Value), !.
calc_attribute(X, Attribute, Value) :-
\+ attribute(X, Attribute, Value),
parent_class(X, Parent),
calc_attribute(Parent, Attribute, Value).
现在攻击变得容易:
attack(X, Value) :-
calc_attribute(X, attack_bonus, Bonus),
calc_attribute(X, base_stat, Base),
calc_attribute(X, level, Level),
Value is (Level + Base) * Bonus.
不过,我们需要更多地概括一下才能到达我们可以写的地方compute
,因为理想情况下,我们想说一些类似的东西compute(fire_warrior, attack, Value)
。要做到这一点,我们需要知道它attack_bonus
是相关的attack
,但我们不知道。让我们稍微重构attribute
一下:
% these are the attack bonuses
attribute(base, bonus(attack), 0).
attribute(red_faction, bonus(attack), 1.5).
attribute(blue_faction, bonus(attack), 1).
% base stats
attribute(character, base_stat, 8.0).
attribute(fire_warrior, level, 1.0).
现在我们正在做饭:
compute(X, Attribute, Value) :-
calc_attribute(X, bonus(Attribute), Bonus),
calc_attribute(X, base_stat, Base),
calc_attribute(X, level, Level),
Value is (Level + Base) * Bonus.
瞧:
?- compute(fire_warrior, attack, Value).
Value = 13.5.
我希望这就是你想要的。:)
大编辑
为了好玩,我想我会看看 Logtalk 会是什么样子,Logtalk是 Prolog 的一种面向对象的扩展语言。我对 Logtalk很陌生,所以这可能是也可能不是一个好方法,但它确实“成功了”,所以让我们看看它是否更符合您的要求。一、基础对象:
:- object(base).
:- public(base_stat/1).
:- public(attack/1).
:- public(bonus/2).
:- public(level/1).
:- public(compute/2).
bonus(attack, 0).
base_stat(0).
level(0).
compute(Attribute, Value) :-
::bonus(Attribute, Bonus),
::base_stat(Base),
::level(Level),
Value is (Level + Base) * Bonus.
:- end_object.
这基本上定义了我们将要存储的关于每件事的事实,以及如何计算您感兴趣的属性。接下来我们建立对象层次结构:
:- object(character, extends(base)).
base_stat(8.0).
:- end_object.
:- object(npc, extends(character)).
:- end_object.
:- object(enemy, extends(npc)).
:- end_object.
:- object(red_faction, extends(enemy)).
bonus(attack, 1.5).
bonus(speed, 1.25).
bonus(defense, 0.25).
:- end_object.
:- object(blue_faction, extends(enemy)).
bonus(attack, 1).
bonus(speed, 1).
bonus(defense, 1).
:- end_object.
:- object(fire_warrior, extends(red_faction)).
level(1.0).
holding(nothing).
:- end_object.
:- object(water_consort, extends(blue_faction)).
level(1.0).
holding(nothing).
:- end_object.
现在使用它非常简单:
?- fire_warrior::compute(attack, X).
X = 13.5.
?- water_consort::compute(attack, X).
X = 9.0.
我希望这有帮助!