如何在 Prolog 中实现“我是我自己的爷爷"? [英] How can I implement, "I am my own Grandpa", in Prolog?

查看:90
本文介绍了如何在 Prolog 中实现“我是我自己的爷爷"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下故事来自 N. Wirth (1976) 算法 + 数据结构 = 程序.

The following story is from N. Wirth's (1976) Algorithms + Datastructures = Programs.

我娶了一个寡妇(我们称她为 W)谁有一个成年女儿(称她为D).拜访我们的父亲(F)很多时候,爱上了我的继女并娶了她.因此,我的父亲成了我的女婿,我的继女成了我的妈妈.一些几个月后,我妻子生了一个儿子(S1),谁成为我父亲的姐夫,还有作为我的叔叔.我父亲的这个妻子,也就是说,我的继女,也有一个儿子(S2).

I married a widow (let's call her W) who had a grown-up daughter (call her D). My father (F), who visited us quite often, fell in love with my step-daughter and married her. Hence, my father became my son-in-law and my step-daughter became my mother. Some months later, my wife gave birth to a son (S1), who become the brother-in-law of my father, as well as my uncle. This wife of my father, that is, my step-daughter, also had a son (S2).

我正在尝试在序言中对这些关系进行建模,因此最终我将能够输入:

I'm attempting to model these relations in prolog so eventually I'll be able to type:

| ?- grandfather(i,i).

而且我会得到一个是"或否"的答案,以确定我是否是我自己的爷爷.

And I'll be given a "Yes", or a "No" on whether or not I'm my own grandpa.

这是我到目前为止编写的代码(grandpa.pl):

Here is the code I have written so far (grandpa.pl):

aunt(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    female(X).

brother(X,Y):-
    sibling(X,Y),
    male(X).

brother_in_law(X,Y):-
    child(X,Z),
    married(Z,W),
    parent(W,Y),
    not(sibling(X,Y)),
    male(X).

brother_in_law(s1,f).

child(X,Y):-
    parent(Y,X).

daughter(X,Y):-
    parent(Y,X),
    child(X,Y),
    female(X).

daughter(d,w).

father(X,Y):-
    parent(X,Y),
    male(X).

father(f,i).

father_in_law(X,Y):-
    child(X,Z),
    married(Y,Z),
    not(child(X,Y)),
    male(X).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

grandmother(X,Y):-
    grandparent(X,Y),
    female(X).

grandfather(X,Y):-
    grandparent(X,Y),
    male(X).

grandchild(X,Y):-
    child(X,Z),
    child(Z,Y).

married(X,Y):-
    wife(X,Y),
    female(X).

married(X,Y):-
    husband(X,Y),
    male(X).

married(i,w).
married(f,d).

mother(X,Y):-
    parent(X,Y),
    female(X).

parent(X,Y):-
    child(Y,X).

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y).

sister(X,Y):-
    sibling(X,Y),
    female(X).

son(X,Y):-
    parent(Y,X),
    male(X).

son(s1,w).
son(s2,d).

son_in_law(X,Y):-
    child(X,Z),
    not(child(X,Y)),
    married(Z,Y),
    male(X).

son_in_law(f,i).

step_daughter(X,Y):-
    child(X,Z),
    married(Z,Y),
    not(child(X,Y)),
    female(X).

step_daughter(d,i).

step_parent(X,Y):-
    married(X,Z),
    parent(Z,Y),
    not(parent(X,Y)).

step_father(X,Y):-
    step_parent(X,Y),
    male(X).

step_mother(X,Y):-
    step_parent(X,Y),
    female(X).

step_mother(d,i).

uncle(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    male(X).

uncle(s1,i).

现在我在循环定义方面遇到了很多麻烦,因此在运行查询时进入无限循环:grandfather(i,i).

Right now I'm having a lot of trouble with circular definitions so that I get into infinite loops when running the query: grandfather(i,i).

例如,我有:

(1 毫秒)是 {trace} |?-祖父(i,i).1 1 调用:grandfather(i,i) ?
2 2 调用:祖父母(i,i) ?
3 3 调用:parent(i,_103) ?
4 4 调用:child(_127,i) ?
5 5 调用:parent(i,_151) ?
6 6 调用:child(_175,i) ?
7 7 调用:parent(i,_199) ?
8 8 调用:child(_223,i) ?
9 9 调用:parent(i,_247) ?
10 10 调用:child(_271,i) ?
11 11 调用:parent(i,_295) ?
12 12 调用:child(_319,i) ?
13 13 调用:parent(i,_343) ?
14 14 调用:child(_367,i) ?
15 15 调用:parent(i,_391) ?
...

(1 ms) yes {trace} | ?- grandfather(i,i). 1 1 Call: grandfather(i,i) ?
2 2 Call: grandparent(i,i) ?
3 3 Call: parent(i,_103) ?
4 4 Call: child(_127,i) ?
5 5 Call: parent(i,_151) ?
6 6 Call: child(_175,i) ?
7 7 Call: parent(i,_199) ?
8 8 Call: child(_223,i) ?
9 9 Call: parent(i,_247) ?
10 10 Call: child(_271,i) ?
11 11 Call: parent(i,_295) ?
12 12 Call: child(_319,i) ?
13 13 Call: parent(i,_343) ?
14 14 Call: child(_367,i) ?
15 15 Call: parent(i,_391) ?
...

这是因为 child 将自己定义为 has have a parent,而 parent 定义自己拥有一个 child(正如您在我发布的上述谓词中所见).

This is because child defines itself as has having a parent, and parent defines itself has having a child (as you'll see in the above predicates I posted).

谁能帮我重新定义这些关系的谓词,以便我可以确定我是否是我自己的爷爷?

Can anyone help me re-define my predicates for these relationships so that I can determine if I'm my own grandpa?

推荐答案

我删除了您代码中不必要的所有内容并更改了一些内容,这就是我的最终结果:

I removed everything that was unnecessary in your code and changed a few things and this is what I ended up with:

% married(Husband, Wife)
married(i,w).
married(f,d).

有人会假设 married(X,Y) :-written(Y,X),但这会导致讨厌的循环证明,所以我们只会按照惯例把丈夫放在第一位.

One would suppose that married(X,Y) :- married(Y,X), but it leads to nasty circular proofs, so we will just put the husband first by convention.

关于为人父母,也出现了类似的问题.我们需要将继父母视为真正的父母,因为谜语取决于它.我们知道您永远无法成为自己的生物祖先!

About parenthood, similar problem arises. We need to consider step parents as real parents, because the riddle depends on it. We know you can never be your own biological ancestor!

然而,parent(X,Y) :- parent(Z,Y),written(X,Z) 遇到了同样的问题,所以我只做了 bio_parent 表示亲生父母.

However, parent(X,Y) :- parent(Z,Y), married(X,Z) runs into the same problems, so I just made bio_parent denote biological parenthood.

bio_parent(f,i).
bio_parent(w,d).
bio_parent(w,s1).
bio_parent(i,s1).
bio_parent(d,s2).
bio_parent(f,s2).

请注意,我们必须明确提及父母双方,因为无法从婚姻中得出亲生父母身份!此外,您的规范方式有问题.你有这样的事情:

Note that we have to be explicit about both parents, as there is no way to conclude biological parenthood from marriage! Also, your way of specification was problematic. You had something like:

son(X,Y) :- child(X,Y), male(X).
son(a,b).

然而,根据这些规则 Prolog 无法推断 child(a,b),所以你最终得到了不是孩子的儿子!这在您的代码中发生了几次.如果您从 a 导出 b,请始终将 a 声明为事实!乍一看,这似乎是 Prolog 的一个缺点,但事实并非如此.请记住,每个子句只是证明某个谓词的一种方式.在上面的例子中,你说每个男孩都是儿子,而且 a 恰好是 b 的儿子.没有任何地方说成为男孩是一个人成为儿子的唯一途径,a 可能只是个例外.

However, from these rules Prolog could not infer child(a,b), so you ended up whith sons who were not children! This occured a few times in your code. If you derive b from a, always state a as the fact! At first glance, this might seem like a shortcoming of Prolog's, but it isn't. Remember that every clause is just one way of proving a certain predicate. In the example above, you stated that every male child is a son, and also a just so happens to be a son of b. Nowhere it is said that being a male child is the only way that someone could be a son though, a might just be the exception.

下一个有点罗嗦,因为我们对 married 的定义迫使我们将继父与继母分开对待.我们统一他们做继父母立即.

The next one is a bit wordy as our definition of married forces us to treat step fathers separately from step mothers. We unify them to step parents immediately though.

step_father(X,Y) :- married(X,Z),bio_parent(Z,Y),\+bio_parent(X,Y).
step_mother(X,Y) :- married(Z,X),bio_parent(Z,Y),\+bio_parent(X,Y).
step_parent(X,Y) :- step_father(X,Y).
step_parent(X,Y) :- step_mother(X,Y).

正如我上面所说,我们需要将继父母视为父母!

As I said above, we need to consider step-parents as parents!

parent(X,Y) :- step_parent(X,Y).
parent(X,Y) :- bio_parent(X,Y).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

我删除了您的代码中还有一些其他错误,我只是向您展示了一些示例,以便您可以从中学习.

There were also some other mistakes in your code which I took out, I just show you some examples so you can learn from it.

首先,这里你说女妻已婚,男夫已婚.因此,男性妻子将未婚.应该反过来说,已婚女性被称为妻子!

First, here you say that female wives are married, and male husbands are married. So, male wives would be unmarried. Should be the other way round though, female married people are called wives!

% wrong:
%
% married(X,Y):-
%    wife(X,Y),
%    female(X).
%
% married(X,Y):-
%    husband(X,Y),
%    male(X).
% 
% right:
% wife(X,Y) :- married(Y,X). % according to our new definition of 'married'
% husband(X,Y) :- married(X,Y).

在这里我添加了最后一行,因为您通常不认为自己是自己的兄弟:

Here I added the last line, as you don't usually consider yourself your own sibling:

% sibling(X,Y):-
%    parent(Z,X),
%    parent(Z,Y),
%    X \= Y. % added this

最后两个是错误谓词的事实.你基本上覆盖了 Prolog 的与他们一起扣除.他们应该被扣除,而不是作为事实陈述!

Those last two are facts on the wrong predicate again. You basically override Prolog's deduction with them. They should be deducted, not stated as facts!

% son_in_law(f,i).
% step_mother(d,i).

现在,试试这样的程序.不要感到惊讶:您不会是唯一一个成为他们自己的祖父母的人!;-)

Now, try the program like this. And don't be surprised: You will not be the only one to be their own grandparent! ;-)

这篇关于如何在 Prolog 中实现“我是我自己的爷爷"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆