list - SWI-Prolog : How to stop the predicate when the list is empty?(包括谓词)

标签 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 是学生已修读的类(class)的给定列表。如果还给出了 C,则谓词应检查学生是否拥有 C 的所有必修类(class)。如果 C 是变量,则通过回溯,谓词应一次生成学生现在可以选修的一门类(class)。类(class)可以按任何顺序排列,但每门类(class)只能生成一次,并且您不应返回学生已修读的任何类(class)。

示例:

?- 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 语句...所以我想要的是让它在第二行或最后一行返回 true 时停止。对于我的作业,我不允许使用剪切运算符!,还有其他方法吗?

最佳答案

(我假设您可以第二次参加某门类(class),即使您已经参加过该类(class)。这至少是我所知道的规则。)

You can take a course, provided you have taken all required courses already.

Prolog 中没有直接的“全部”。但你可以用不同的方式来表述

You can take a course, provided there is no required course that you have not taken already.

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].
%       ^^^^^^^^

<子><上> 免责声明
您的问题本质上是非单调的:通过为要求添加更多事实,您可以减少可能参加的类(class)数量。作为初学者,最好坚持解决本质上单调的问题。 Prolog 在这方面真正擅长。

关于list - SWI-Prolog : How to stop the predicate when the list is empty?(包括谓词),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55170614/

相关文章:

matlab - 如何将此文本文件制作成 MATLAB 中的列表?

javascript - 在循环中附加 HTML 元素

python - 创建未知数量的以编程方式定义的变量

lambda - Prolog 中的 Binder

包装值的 Prolog 添加

Prolog 和祖先关系

c++ - 读取 txt 文件并将值放入列表中 (c++)

Python-文件的列平均值

从列表/字典中删除项目后,Python "sys.getsizeof"报告大小相同?

python - 用空格分隔相邻相同字符的递归函数