在Prolog中比较列表元素结构

在Prolog中比较列表元素结构,prolog,Prolog,我在学习时使用SWI Prolog处理示例问题。我已经到了这个问题的最后一部分,在这里我必须递归地(我希望)比较包含“研究者”结构的列表的元素,以确定研究者是否有相同的姓氏,如果有,返回该列表的组长的名字和姓氏 只有一个名单符合这一标准,它有四名成员,都是同一个姓氏。但是,正确答案会返回四次。我觉得我的解决方案不雅观,缺乏吸引力。问题是: 以下Prolog数据库代表学科教学团队。 % A research group structure takes the form % group(Crew,

我在学习时使用SWI Prolog处理示例问题。我已经到了这个问题的最后一部分,在这里我必须递归地(我希望)比较包含“研究者”结构的列表的元素,以确定研究者是否有相同的姓氏,如果有,返回该列表的组长的名字和姓氏

只有一个名单符合这一标准,它有四名成员,都是同一个姓氏。但是,正确答案会返回四次。我觉得我的解决方案不雅观,缺乏吸引力。问题是:

以下Prolog数据库代表学科教学团队。

% A research group structure takes the form
% group(Crew, Leader, Assistant_leader).
%
% Crew is a list of researcher structures,
% but excludes the researcher structures for Leader
% and Assistant_leader.
%
% researcher structures take the form
% researcher(Surname, First_name, expertise(Level, Area)).

group([researcher(giles,will,expertise(3,engineering)),
researcher(ford,bertha,expertise(2,computing))],
researcher(mcelvey,bob,expertise(5,biology)),
researcher(pike,michelle,expertise(4,physics))).

group([researcher(davis,owen,expertise(4,mathematics)),
researcher(raleigh,sophie,expertise(4,physics))],
researcher(beattie,katy,expertise(5,engineering)),
researcher(deane,fergus,expertise(4,chemistry))).

group([researcher(hardy,dan,expertise(4,biology))],
researcher(mellon,paul,expertise(4,computing)),
researcher(halls,antonia,expertise(3,physics))).

group([researcher(doone,pat,expertise(2,computing)),
researcher(doone,burt,expertise(5,computing)),
researcher(doone,celia,expertise(4,computing)),
researcher(doone,norma,expertise(2,computing))],
researcher(maine,jack,expertise(3,biology)),
researcher(havilland,olive,expertise(5,chemistry))).
根据这些信息,编写可用于返回以下内容的Prolog规则(以及所需的任何附加谓词):

船员人数超过一人且姓氏相同的任何领导的名字和姓氏。[4分]

这是我目前使用递归的解决方案,尽管对于列表中的每个成员来说效率不高,但它会将该成员与其他每个成员进行比较。因此,由于正确的列表有四个成员,因此它会返回四次“jack maine”

surname(researcher(S,_,_),S).

checkSurname([],Surname):-
    Surname==Surname. % base case 

checkSurname([Researcher|List],Surname):-
    surname(Researcher,SameSurname),
    Surname == SameSurname,
    checkSurname(List,SameSurname).

q4(Forename,Surname):-
    group(Crew,researcher(Surname,Forename,_),_),
    length(Crew,Length),
    Length > 1,
    member(researcher(SameSurname,_,_),Crew),
    checkSurname(Crew,SameSurname).
如果没有重复的结果和每次都对每个成员进行冗余比较,我怎么能做到这一点?对于我所采取的每一种方法,我每次都会被“SameSurname”作为一个单例留下,因此不得不在q4谓词中强制使用它两次

电流输出

    13 ?- q4(X,Y).
    X = jack,
    Y = maine ;  x4

你做的事情比必须做的更复杂。您的
q4/2
可能更简单:

q4(First_name, Surname) :-
    group(Crew, researcher(Surname, First_name, _E), _A),
    length(Crew, Len), Len > 1,
    all_same_surname(Crew).
现在您只需要定义
所有相同的姓氏/1
。想法很简单:取第一名船员的姓氏,与其他船员的姓氏进行比较:

all_same_surname([researcher(Surname, _FN, _E)|Rest]) :-
    rest_same_surname(Rest, Surname).

rest_same_surname([], _Surname).
rest_same_surname([researcher(Surname, _FN, _E)|Rest), Surname) :-
    rest_same_surname(Rest, Surname).
(显然,如果没有机组成员,
所有相同姓氏/1
会立即失败)

应该是这样,除非我误解了问题陈述

?- q4(F, S).
F = jack,
S = maine.
怎么样

注意:解决方案只是采用最直接的方法来回答问题,并且易于书写和阅读。有很多事情可以做,否则。由于没有理由不这样做,我在谓词的头部使用了模式匹配和统一,而不是在主体或额外谓词中使用比较来从复合词中提取参数


另外,想想
member/2
做了什么(甚至在库中查找它的定义),您将看到解决方案中所有额外的选择点来自何处。

您正在做的事情比必须做的更复杂。您的
q4/2
可能更简单:

q4(First_name, Surname) :-
    group(Crew, researcher(Surname, First_name, _E), _A),
    length(Crew, Len), Len > 1,
    all_same_surname(Crew).
现在您只需要定义
所有相同的姓氏/1
。想法很简单:取第一名船员的姓氏,与其他船员的姓氏进行比较:

all_same_surname([researcher(Surname, _FN, _E)|Rest]) :-
    rest_same_surname(Rest, Surname).

rest_same_surname([], _Surname).
rest_same_surname([researcher(Surname, _FN, _E)|Rest), Surname) :-
    rest_same_surname(Rest, Surname).
(显然,如果没有机组成员,
所有相同姓氏/1
会立即失败)

应该是这样,除非我误解了问题陈述

?- q4(F, S).
F = jack,
S = maine.
怎么样

注意:解决方案只是采用最直接的方法来回答问题,并且易于书写和阅读。有很多事情可以做,否则。由于没有理由不这样做,我在谓词的头部使用了模式匹配和统一,而不是在主体或额外谓词中使用比较来从复合词中提取参数


另外,想一想
member/2
做了什么(甚至在库中查找它的定义),您将看到您的解决方案中所有额外的选择点都来自哪里。

Boris已经回答了这个问题,但我想展示我能提供的最简洁的解决方案。这只是出于教育目的(推广
findall/3
maplist/2
):


Boris已经回答了这个问题,但我想展示我能提供的最简洁的解决方案。这只是出于教育目的(推广
findall/3
maplist/2
):


紧凑高效的解决方案:

q4(F, S) :-
    group([researcher(First,_,_), researcher(Second,_,_)| Crew], researcher(S, F, _), _),
    \+ (member(researcher(Surname, _, _), [researcher(Second,_,_)| Crew]), First \== Surname).
?- q4(X,Y).
X = jack,
Y = maine.
调用示例(生成单个解决方案):


紧凑高效的解决方案:

q4(F, S) :-
    group([researcher(First,_,_), researcher(Second,_,_)| Crew], researcher(S, F, _), _),
    \+ (member(researcher(Surname, _, _), [researcher(Second,_,_)| Crew]), First \== Surname).
?- q4(X,Y).
X = jack,
Y = maine.
调用示例(生成单个解决方案):


哦,哇-我没有意识到我可以像那样标记通配符条目,这更清楚:)那太完美了,完全符合预期。使用
member
来匹配“SameSurname”是一个非常糟糕的尝试,但这两种方法都很好——我没有想到会让整个团队都参与进来。谢谢@不要忘记接受答案。我相信会有其他人试图解决同样的问题。如果我们幸运的话,他们会在询问之前进行搜索。哦,哇-我没意识到我可以这样标记通配符条目,这更清楚:)这太完美了,完全符合预期。使用
member
来匹配“SameSurname”是一个非常糟糕的尝试,但这两种方法都很好——我没有想到会让整个团队都参与进来。谢谢@不要忘记接受答案。我相信会有其他人试图解决同样的问题。如果我们幸运的话,他们会在询问之前进行搜索。
呢?-q4(X,Y)?@用户您意识到,放弃您不完全理解的副作用选择点并不是很好。。。清洁?那
呢?-q4(X,Y)?@用户您意识到,放弃您不完全理解的副作用选择点并不是很好。。。清洁的