【问题标题】:Prolog predicate issueProlog谓词问题
【发布时间】:2017-12-30 09:49:01
【问题描述】:

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

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

例如 G = [person(kara, [barry, clark]),person(bruce, [clark, Oliver]),person(barry, [kara, Oliver]),person(clark, [oliver, 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 函数的某个地方。 “likers”的输出:

?- 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] 或其中一种组合。有没有办法在纯序言中得到它?

【问题讨论】:

  • 您能否发布更多输入数据来测试程序?另请注意,您发布的程序不起作用(likes/3member_/2 不存在)。
  • 1) G 代表什么?? 2) 为什么X 应该friendly(G, X)G = [person(alice,[bob]),person(bob,[])] 成功??
  • 对不起,我添加了缺少的代码并进行了一些编辑。
  • 您是否可能误解了说明? person/2 子句可能应该在数据库中,而不是在列表中传递。
  • 请发布代码,而不是图片。

标签: prolog


【解决方案1】:

静下心来,稍微google了一下,这里有一个应该满意的答案。关键思想是不仅要传递我们感兴趣的人 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

【讨论】:

    【解决方案2】:

    你的程序应该是这样写的:

    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 结果 - 根据我对您提供的数据和规则的检查,这是正确的。

    【讨论】:

    • 请查看编辑,因为我解释了 Barry 的答案。
    【解决方案3】:

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

    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,则需要自己再写三行左右的代码。

    【讨论】:

    • 你说得对,我们不允许使用 findall。但是,如果不允许任何内置谓词或控制结构,我怎么能编写自己的 findall。我想这就是我试图用我的“喜欢”谓词做的,但它并不完美。
    • 见第二个答案。
    • 另外,Bruce 被认为是友好的,因此我们可以从代码中删除“Fs \= []”。
    【解决方案4】:

    你可以这样写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).
    

    【讨论】:

    • 这包括我们不允许的析取运算符。一定有别的办法。
    • \+ 也是一个不允许的控制运算符 :( 不允许控制运算符,只有提到的纯序言。
    • 也许您当时可以在问题中指定所有这些 BS。
    • 我做到了。我说没有内置的东西。只有纯序言。
    • 我从未听说过任何不允许否定的“纯序言”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多