我正在写一个顾问计划,为下一学期的学生选择课程。其中一项任务是检查学生是否具备所有先决条件。到目前为止,我已经:
hasPrereqs(Student, Class) :-
(prereq(Pre, Class) ->
hasClass(Student, Pre);
true).
hasClass(Student, Class) :-
(creditFor(Student, Class);
currentlyTaking(Student, Class)).
先决条件声明如下:
prereq(csc140, csc145).
prereq(csc140, csc180).
prereq(csc140, csc198).
prereq([csc140, csc130], csc201).
prereq(csc145, csc201).
这适用于所有可能性,除非另一个类需要两个类(如csc201
,其中学生可以选择csc140和csc130或只是csc140)。我认为列表是要走的路,但我无法弄清楚如何实现它。
我尝试创建另一个hasPrereqs
,如下所示:
hasPrereqs(Student, Class) :-
forall(prereq(Pre, Class),
(compound(Pre) ->
hasClass(Student, Pre)).
这个不起作用,因为Pre
是一个列表,而不是一个直的原子,因此:
creditFor(somekittens, csc130).
creditFor(somekittens, csc140).
/* Returns false, because I don't have credit for the list, just the two classes */
creditFor(somekittens, [csc130, csc140]).
如何设置系统以便需要其他几个类的类才能正常工作?
答案 0 :(得分:1)
我会这样做:
hasPrereqs(Student, Class) :-
prereq(Class, Pres),
forall(member(Pre, Pres), hasClass(Student, Pre)).
hasClass(Student, Class) :-
(creditFor(Student, Class);
currentlyTaking(Student, Class)).
prereq(csc140, []).
prereq(csc145, [csc140]).
prereq(csc180, [csc140]).
prereq(csc198, [csc140]).
prereq(csc201, [csc140, csc130]).
prereq(csc201, [csc145]).
我在prereq/2
上交换了参数的顺序,并将先决条件设为一个列表,无论有多少。这使得使用prereq/2
的代码更加一致,并为没有先决条件的类提供符号,即prereq(foo, [])
。
然后我使用forall/2
和member/2
来确保学生满足所有先决条件。
答案 1 :(得分:0)
任何来自函数式编程背景的人(比如我!)都希望这样做:
foreach(var i=0;i<Class.length;i++) {
if(!hasClass(Student, Class[i])) {
return false;
}
}
return true;
不幸的是,这不起作用。在我的知识中没有简单的方法遍历Prolog中的列表并返回true
IFF返回的所有元素都是真的。而是使用递归方法遍历列表。添加hasClass
的另一个定义,如下所示:
hasClass(Student, ClassList) :-
/* Splits up the list into:
H = the first element of the list as an atom
T = The rest of the list elements as a list
(if there's only one list element, T is equal to []) */
[H|T] = ClassList,
hasClass(Student, H),
/* if T isn't equal to [], recursively check the rest of the list's elements */
(T \= [] -> hasClass(Student, T);true).
答案 2 :(得分:0)
hasPrereqs(Student, Class) :-
(prereq(Pre, Class) ->
hasClass(Student, Pre);
true).
无论变量实例和您拥有的实际数据如何,始终为真。 唯一的目的可能是由prereq / 2或hasClass / 2执行的一些副作用(如IO或DB修改),这似乎不是。
现在回答。 SWI-prolog有is_list / 1和maplist / 2,后者可以对每个元素重复相同的测试,只有当测试在所有元素上成功时才为真:
编辑类意味着Pre
hasPrereqs(Student, Class) :-
forall(prereq(Pre, Class),
( is_list(Pre)
-> maplist(hasClass(Student), Pre)
; hasClass(Student, Pre)
)).
或更好,如果您计划仅重复使用hasClass进行测试,并假设已经工作的hasClass / 2
hasPrereqs(Student, Class) :-
forall(prereq(Pre, Class), hasClass(Student, Pre)).
hasClass(Student, Classes) :-
is_list(Classes) -> maplist(hasClass(Student), Classes).
编辑以下是错误的,在最后一次通话时循环...
又一种方式。在你的回答中,你接近解决方案:
hasClass(Student, ClassList) :-
( [H|T] = ClassList
-> hasClass(Student, H), hasClass(Student, T)
; hasClass(Student, ClassList)
).
编辑解决方案应该更简单:
hasClass(Student, [Class|ClassList]) :-
hasClass(Student, Class),
!, hasClass(Student, ClassList).
hasClass(_Student, []).