0

我只是无法解决我在prolog中遇到的这个问题。才刚刚开始,但我似乎无法找到一种方法来确定一个对象是否是唯一的。这是我的代码:

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

我怎样才能知道一个学生是否是独一无二的。以斯图尔特为例,有两个学生叫斯图尔特,所以斯图尔特不是唯一的。我如何编写一个程序来判断它是否是另一个名为 Stuart 的学生。

我试过在这上面花了很多时间,但我似乎无法处理原来的斯图尔特而不是另一个斯图尔特,因为我不能排除我试图找出它是否独特的那个.

谢谢您的帮助。

4

3 回答 3

2

使用您的数据库示例,这可以做到

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

因为它产生

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

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

使用这样的元谓词:

%%  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).

相同的谓词可以使用来自 library(aggregate) 的 aggregate_all(count, student(S,_), 1),但是这样的库目前在内部构建一个列表,那么您可以认为 Peter 的答案更容易实现。

于 2013-03-10T10:00:18.577 回答
2

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

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

这段代码说“找到一个长度与姓名相同的学生数量的列表”,然后“使 Count 与列表的长度相同”:

% 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 解决方案,因为您不能说“给我一个唯一的学生姓名”之类的话并获得所有唯一姓名的列表。

于 2013-03-09T20:26:14.440 回答
1

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

Student(Ross).

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

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

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

现在这个问题已经解决了,目前还不清楚你的目标是什么。你打算怎么处理你独特的学生?你怎么知道第一个是你要找的,而不是第二个?为什么不使用学生编号(至少在您的示例中,两个 Stuarts 似乎有不同的编号)?

于 2013-03-09T16:15:46.317 回答