2012-10-26 37 views
0

我正在编写一个顾问程序,为学生选择下一个学期的课程。其中一项任务是检查学生是否具备所有先决条件。到目前为止,我有:测试以查看列表/变量的所有元素是否为真

hasPrereqs(Student, Class) :- 
    (prereq(Pre, Class) -> 
     hasClass(Student, Pre); 
    true). 

hasClass(Student, Class) :- 
    (creditFor(Student, Class); 
    currentlyTaking(Student, Class)). 

prereqs被宣布为:

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

一些建议:'prereq/2':将所有必需的类放入列表中。即使只有一个。即使没有 - 这将是一个空的列表。 – false

+0

与我现在正在做的事情相比,这会是一个优势吗? (另外,很好的用户名,特别是对于Prolog的问题。) – SomeKittens

+0

它会更统一(不再有特殊的外壳) - 它可以顺利地解决你的问题,并且可以替代先决条件。 – false

回答

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/2member/2来确保学生符合所有先决条件。

+0

干得好。看起来我有一些重构要做。 – SomeKittens

0

任何人谁是从一个函数式编程背景的人(!像我)想这样做:

foreach(var i=0;i<Class.length;i++) { 
    if(!hasClass(Student, Class[i])) { 
     return false; 
    } 
} 
return true; 

不幸的是,这是行不通的。根据我的知识,没有简单的方法来遍历Prolog中的列表并返回true IFF所有元素都返回true。相反,使用递归方法遍历列表。添加另一个定义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). 
0
hasPrereqs(Student, Class) :- 
    (prereq(Pre, Class) -> 
     hasClass(Student, Pre); 
    true). 

总是真实,不论变量实例化,你有实际的事实数据。 唯一的目的可能是由prereq/2或hasClass/2执行的一些副作用(如IO或数据库修改),并且这看起来似乎不是。

现在来回答。 SWI-Prolog有is_list/1和maplist/2,后者可以重复每个元件上的相同的测试,为真只有在测试上的所有元素成功:

编辑类的意思是预

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, []). 
相关问题