course(cmput325).
course(cmput175).
course(cmput201).
course(cmput204).
prerequisite(cmput204, cmput325).
prerequisite(cmput175, cmput201).
prerequisite(cmput175, cmput204).
我需要写一个新的谓词
can_take(+L,?C).
定义:
L是学生已经参加的课程列表。如果还提供了C,则谓词应检查学生是否具有C的所有必修课程。如果C是变量,则通过回溯,谓词应一次生成一门课程,以便学生现在就可以学习。课程可以按任何顺序进行,但是每门课程只能生成一次,并且您不应该返回学生已经参加的任何课程。
示例:
?- findall(C, can_take([cmput175], C), L).
should return
L = [cmput201, cmput204].
这是我的谓词:
can_take(L,C) :- prerequisite(L,C).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
此谓词未返回正确的结果,只是返回了false。我认为这是因为我没有确定L为空时的条件,但是,如果我尝试在其中一个中添加L \ == []的话。它仍然给我错误...我该怎么做才能使该谓词停止并给我结果?
-------更新-------
pre(X,C) :- prerequisite(X,C).
pre(X,C) :- prerequisite(X,Y), pre(Y,C).
pre2(C,L) :- findall(L1,pre(L1,C),L).
required(C,L) :- pre2(C,L1),sort(L1,L).
can_take([],_).
can_take(L,C) :- required(C,L).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
这是我的代码测试:
?- required(cmput325,L).
L = [cmput175, cmput204].
?- required(cmput204,L).
L = [cmput175].
?- can_take([cmput175],X).
X = cmput201 ;
X = cmput204 ;
?- findall(C, can_take([cmput175], C), L).
L = [cmput201, cmput204].
?- can_take([cmput204],cmput325).
false. (this one is OK)
?- can_take([cmput175,cmput204],cmput325).
true ;
false. (this one is OK)
?- can_take([cmput175],cmput204).
true ;
true ;
false.
最后一个不行,因为我不希望它返回两个真实的语句...所以我想要的就是让它在第二行或最后一行返回true时停止。对于我的作业,不允许使用cut运算符!,还有其他方法吗?
答案 0 :(得分:3)
(我假设即使您已经上过这门课,您也可以再次参加。这至少是我所知道的规则。)
前提是您已经选修了所有必修课程,就可以选修课程。
Prolog中没有直接的“全部”。但是你可以用不同的方式表达
如果没有尚未参加的必修课程,则可以参加。
can_take(Takens, Next) :-
course(Next),
iwhen( ground(Takens),
\+ ( prerequisite(Required, Next), \+ member(Required, Takens) ) ).
这使用iwhen/2
来防止Takens
未完全实例化的情况。
请注意,您的示例稍有不同:
?- findall(C, can_take([cmput175], C), L).
L = [cmput175, cmput201, cmput204].
% ^^^^^^^^
免责声明
您的问题本质上是非单调的:通过增加需求的事实,您正在减少可能修读的课程。作为初学者,宁愿坚持本质上单调的问题。正是Prolog在这方面真正出类拔萃。