プロローグへようこそ!試してみてよかったです。たくさんの想像力を持っているように見えるので、それがあなたの想像力に役立つことを願っています!
ここでは、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)
. 実際の違いの 1 つは、 が のようis
な代数式を評価する方法を知っていることです。(最初から Prolog を使用し、代わりにを使用すると、Prolog の方がはるかに理にかなっていることがわかると事前に警告します。)(X + Y) / 2
div(plus(X, Y), 2)
clpfd
#=
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).
これがあなたが求めていることに関連しているかどうかはわかりませんが、参考になるかもしれないので、そこにあります。
もちろん、もう 1 つの可能性は、パラメータ化することです。元のコードを取得して、生徒ごとにパラメーター化できます。
avg_score(Student1, Student2, Z) :-
student(Student1, X),
student(Student2, Y),
Z is (X + Y) / 2.
これは、動物誌を照会するのにより適しているようです。あなたが尋ねるのではなく、尋ねるattack(X)
でしょうattack(fire_warrior, X)
。
Prolog を初めて使うあなたを Logtalk に送り込むのは嫌ですが、探している答えのいくつかが含まれているのではないかと思います。バニラの 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
失敗した場合はボーナスを 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.
それがあなたの望んだものであることを願っています。:)
大きな編集
楽しみのために、これがProlog のオブジェクト指向拡張言語であるLogtalkでどのようになるか見てみようと思いました。私は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.
これが役立つことを願っています!