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

时间:2019-03-14 19:29:29

标签: list recursion prolog predicate backtracking

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运算符!,还有其他方法吗?

1 个答案:

答案 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在这方面真正出类拔萃。