SWI-Prolog:当列表为空时,如何停止谓词?(包括谓词)


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时让它停止。对于我的作业,我不允许使用剪切操作员!

(我假设您可以第二次参加课程,即使您已经参加了课程。至少这是我知道的规则。)

您可以上一门课程,只要您已经参加了所有必需的课程。

没有直接的"全部"在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确实很擅长。

最新更新