Prolog谓词问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Prolog谓词问题相关的知识,希望对你有一定的参考价值。

我的部分工作有问题。我应该写一个谓词“友好”,当网络成员X被称为友好时,如果X喜欢支持他/她的每个人,那么这应该是真的。

编辑:在下面的例子中,巴里是友好的,因为喜欢巴里的人是卡拉和巴里喜欢卡拉回来的人。卡拉不是正确的答案,因为喜欢卡拉的人的名单是巴里,克拉克和奥利弗但卡拉只喜欢巴里和克拉克,所以卡拉不友好。

例如G = [人(kara,[巴里,克拉克]),人(布鲁斯,[克拉克,奥利弗]),人(巴里,[卡拉,奥利弗]),人(克拉克,[奥利弗,卡拉]),人(奥利弗,[kara])]

到目前为止我所拥有的;

friendly(G, X):- 
    member_(person(X, _), G),
    likers(G, X, L),
    likes_all(G, X, L).

% to get the list of members who like X;

likers(G, X, [Y|T]) :-
    likes(G, Y, X),
    select_(Y, G, G2),
    likers(G2, X, T).
likers([], _, []).
likers([], _, _).
likers(_, _, []).

% select is used to remove the person from the list once visited.

select_(X, [person(X, _)|T], T).
select_(X, [H|T], [H|R]) :-
    select_(X, T, R).

% to check whether X likes all the list of people that like X;

likes_all(G, X, [H|T]):-
    likes(G, X, H),
    likes_all(G, X, T).
likes_all(_, _, []).    
likes_all(G, [H|T], X):-
    likes(G, H, X),
    likes_all(G, T, X).
likes_all(_, [],_).

likes(G, X, Y):- 
    member_(person(X, L), G),
    member_(Y, L).

member_(X, [X|_]).
member_(X, [_|T]) :-
    member_(X, T).

我的问题是它无法正常工作。见下面的示例输出。

所以,我不知道出了什么问题以及我该怎么做。我们不允许使用任何内置的谓词或控制操作符,所以没有!,;,=, =,+等,只有纯粹的序言。

任何前进的暗示都值得赞赏。

输出:

[debug]  ?- friendly([person(kara, [barry, clark]),person(bruce, [clark, oliver]),person(barry, [kara, oliver]),person(clark, [oliver, kara]),person(oliver, [kara])], X).
X = kara ;
X = kara ;
X = kara ;
X = kara ;
X = kara ;
X = bruce ;
X = barry ;
X = barry ;
X = clark ;
X = clark ;
X = oliver ;
false.

我认为我的错误在于喜欢的功能。 “喜欢者”的输出:

?- likers([person(kara, [barry, clark]), person(bruce, [clark, oliver]), person(barry, [kara, oliver]), person(clark, [oliver, kara]), person(oliver, [kara])], kara, L).
L = [] ;
L = [barry] ;
L = [barry, clark] ;
L = [barry, clark, oliver] ;
L = [barry, oliver] ;
L = [barry, oliver, clark] ;
L = [clark] ;
L = [clark, barry] ;
L = [clark, barry, oliver] ;
L = [clark, oliver] ;
L = [clark, oliver, barry] ;
L = [oliver] ;
L = [oliver, barry] ;
L = [oliver, barry, clark] ;
L = [oliver, clark] ;
L = [oliver, clark, barry] ;
false.

在上面,正确的答案是L = [barry,clark,oliver]或其中一个组合。有没有办法在纯粹的prolog中得到它?

答案

平静下来之后,还有一些谷歌,这里的回答应该是令人满意的。关键的想法是不仅传递我们感兴趣的人X而且传递补充集(AEX)。与此相比,相当于否定与X的比较。

friendly(X) :-
  G = [person(kara,[barry,clark]),
       person(bruce,[clark,oliver]),
       person(barry,[kara,oliver]),
       person(clark,[oliver,kara]),
       person(oliver,[kara])],
  allppl(G,All),
  mymember(person(X,Xs),G),
  select(X,All,AEX),
  likers(G,X,AEX,[],Fs),
  subset(Fs,Xs).

获取所有人的列表:

allppl([person(P,_)|Rest],[P|Ps]) :-
  allppl(Rest,Ps).
allppl([],[]).

这是我的老likers/4加补充集。

likers([person(Y,Ys)|Rest],X,AEX,Fs0,Fs) :-
  mymember(X,Ys),
  likers(Rest,X,AEX,[Y|Fs0],Fs).
likers([person(_,Ys)|Rest],X,AEX,Fs0,Fs) :-
  subset(Ys,AEX),
  likers(Rest,X,AEX,Fs0,Fs).
likers([],_,_,Fs,Fs).

这里有一些辅助谓词。

select(X,[X|Xs],Xs).
select(X,[Y|Xs],[Y|Zs]) :-
  select(X,Xs,Zs).

subset([],_).
subset([X|Xs],Ys) :-
  mymember(X,Ys), subset(Xs,Ys).

mymember(X,[X|_]).
mymember(X,[_|Xs]) :-
  mymember(X,Xs).

现在我明白了

?- friendly(X).
X = bruce ? ;
X = barry ? ;
no
另一答案

以下是您的程序应该如何编写:

person(kara,[barry, clark]).
person(bruce,[clark,oliver]).
person(barry,[kara,oliver]).
person(clark,[oliver,kara]).
person(oliver,[kara]).

likes_back([],_).
likes_back([Y|Ys],X) :-
    person(Y,Xs),
    member(X,Xs),
    likes_back(Ys,X).

friendly(X) :-
    person(X,Ys),
    likes_back(Ys,X).

?- friendly(X),write(X),nl,fail.

当我运行它时,我只得到kara - 根据我对你提供的数据和规则的检查,这是正确的。

另一答案

好的,如果我理解正确的话,这是一个解决方案。我认为没有人喜欢的人(布鲁斯)不被认为是友好的。

friendly(P) :-
  person_likes(P,Ps),
  findall(X,(person_likes(X,Zs),member(P,Zs)),Fs), Fs = [],
  check_subset(Fs,Ps).

check_subset([X|Xs],Set) :-
  memberchk(X,Set),
  check_subset(Xs,Set).
check_subset([],_).

person_likes(kara,[barry,clark]).
person_likes(bruce,[clark,oliver]).
person_likes(barry,[kara,oliver]).
person_likes(clark,[oliver,kara]).
person_likes(oliver,[kara]).

结果:

?- friendly(X).
X = barry ? ;
no

如果您不被允许使用findall/3,那么您需要自己编写另外三行代码。

另一答案

你可以像这样写likers/4

likers([person(Y,Ys)|Rest],X,Fs0,Fs) :-
  ( memberchk(X,Ys) ->
    Fs1 = [Y|Fs0]
  ; Fs1 = Fs0 ),
  likers(Rest,X,Fs1,Fs).
likers([],_,Fs,Fs).

用第三个参数空列表调用它。

增加:不带分号:

likers([person(Y,Ys)|Rest],X,Fs0,Fs) :-
  memberchk(X,Ys),
  likers(Rest,X,[Y|Fs0],Fs).
likers([person(_,Ys)|Rest],X,Fs0,Fs) :-
  + memberchk(X,Ys),
  likers(Rest,X,Fs0,Fs).
likers([],_,Fs,Fs).

以上是关于Prolog谓词问题的主要内容,如果未能解决你的问题,请参考以下文章

Prolog 中的谓词控制

Prolog 中的“行为良好的谓词”是啥?

Prolog 中的子列表谓词

Prolog:如何删除谓词中的对称值

Prolog使用在内部谓词之间的列表

Prolog中是不是可以接受具有可变数量的谓词?