【问题标题】:Comparing list element structures to each other in Prolog在 Prolog 中比较列表元素结构
【发布时间】:2014-05-13 04:34:02
【问题描述】:

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

只有一个列表符合此条件,它有四个成员,都具有相同的姓氏。但是,正确答案会返回四次。我觉得我的解决方案不优雅而且缺乏。问题来了:

以下 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(X,Y), !. 呢?
  • @User 你意识到丢弃选择点作为你不完全理解的副作用不是很干净?

标签: prolog


【解决方案1】:

紧凑而高效的解决方案:

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.

【讨论】:

    【解决方案2】:

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

    q4(First_name, Surname) :-
        group(Crew, researcher(Surname, First_name, _E), _A),
        length(Crew, Len), Len > 1,
        all_same_surname(Crew).
    

    现在您只需要定义all_same_surname/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).
    

    (显然,如果没有船员,all_same_surname/1 会立即失败)

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

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

    怎么样?

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

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

    【讨论】:

    • 哇哦 - 我没有意识到我可以像这样标记通配符条目,这更清晰:) 完美,完全符合预期。使用member 来匹配“SameSurname”是一个非常糟糕的尝试,但是这两种方法都可以正常工作——我没想过要把整个船员都传进去。谢谢!
    • @Vixxd 不要忘记接受答案。我相信会有其他人试图解决完全相同的问题。如果我们幸运的话,他们会在询问之前进行搜索。
    【解决方案3】:

    鲍里斯确实已经回答了这个问题,但我想展示我能想到的最简洁的解决方案。仅用于教育目的(宣传findall/3maplist/2):

    q4(F, S) :-
        group(Crew, researcher(S, F, _), _),
        findall(Surname, member(researcher(Surname, _, _), Crew), Surnames),
        Surnames = [ First, Second | Rest ],
        maplist(=(First), [ Second | Rest ]).
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 2023-04-03
      • 2015-09-30
      相关资源
      最近更新 更多