我怎么知道对象是否是唯一的

时间:2013-03-09 14:39:09

标签: prolog logic unique

我无法理解这个与prolog有关的问题。才开始,但我似乎无法找到一种方法来确定一个对象是否是唯一的。继承我的代码:

/* (Student Name, Student Number)*/
Student(stuart, 11234).
Student(ross, 11235).
Student(rose, 11236).
Student(stuart, 11237).

我怎样才能知道学生是否独一无二。以斯图尔特为例,有两名学生名叫斯图尔特,因此斯图尔特并不是独一无二的。我怎么能写一个程序来判断它的另一个学生是否叫斯图尔特。

我已经尝试过花了这么多时间,但我似乎无法理解与最初的斯图尔特而不是其他斯图亚特打交道,因为我无法排除我试图找出的那个如果它的独特之处。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

可能有很多方法可以解决这个问题,但我会这样做:

% a student has a name and a number
student(stuart, 11234).
student(ross, 11235).
student(rose, 11236).
student(stuart, 11237).

此代码显示“查找与姓名学生人数相同的列表”,然后“使计数与列表长度相同”:

% for every student name there is an associated count of how many times 
%   that name appears
number_students(Name, Count) :-
    findall(_, student(Name, _), Students),
    length(Students, Count).

只有number_students为1:

时,此谓词才会成立
% a student name is unique (appears once and only once) is the 
%  number_students count is 1
unique_student(Name) :-
    number_students(Name, 1).

测试:

12 ?- unique_student(ross).
true.

13 ?- unique_student(rose).
true.

14 ?- unique_student(bob).
false.

15 ?- unique_student(stuart).
false.

这是一个解决问题的简单方法,但它不是一个伟大的 Prolog解决方案,因为你不能说“给我一个独特的学生名字”这样的东西,并获得所有的独特的名字。

答案 1 :(得分:2)

使用您的数据库示例,可以执行

unique(S) :-
    student(S, N), \+ (student(S, M), M \= N).

因为它产生

?- unique(S).
S = ross ;
S = rose ;
false.

通常,Prolog的目标是解决方案的存在。然后关于基数的预测需要来自“不纯”的支持。该语言的一部分:nb_setarg当我们需要有效跟踪基数时,它是我们最好的朋友。

使用这样的metapredicate:

%%  count_solutions(+Goal, ?C)
%
%   adapted from call_nth/2 for http://stackoverflow.com/a/14280226/874024
%
count_solutions(Goal, C) :-
    State = count(0, _), % note the extra argument which remains a variable
    (   Goal,
        arg(1, State, C1),
        C2 is C1 + 1,
        nb_setarg(1, State, C2),
        fail
    ;   arg(1, State, C)
    ).

:- meta_predicate count_solutions(0, ?).

你可以在不考虑第二个参数的情况下解决问题

unique(S) :-
    student(S, _), count_solutions(student(S, _), 1).

同一个谓词可以使用库(聚合)中的aggregate_all(count,student(S,_),1),但是这样的库目前在内部构建一个列表,那么你可以认为Peter的答案更容易实现。 / p>

答案 2 :(得分:1)

您对代码的一些评论。这不是事实:

Student(Ross).

这是两个不同的事实(至少在SWI-Prolog中):

student(ross).
student('Ross').

换句话说,谓词名称必须以小写字母开头,以大写字母开头的标识符表示变量,而不是原子。您可以将任何字符串放在单引号中,使其成为有效的原子。

现在已经解决了这个问题,目前还不清楚你的目标是什么。你和你这个独特的学生有什么关系?你怎么知道第一个是你正在寻找的那个,而不是第二个?为什么不使用学号呢(至少在你的例子中,两个Stuarts似乎有不同的数字)?