1

我有以下声明:

calculate_sad_moods([]):-!.
calculate_sad_moods([X2|Rest2]) :- 
    (sad(X2),write(`One of our sad students is: `),write(X2),nl);
calculate_sad_moods(Rest2).

当我这样称呼它时:

?- calculate_sad_moods([
    ivan, dragan, petkan, borislav, damyan, ani, petyr, ivo
]).

我最终得到了一个非常长的列表(没关系,但它有重复的记录):

One of our sad students is: ivan
Yes.
One of our sad students is: dragan
Yes.
One of our sad students is: dragan
Yes.
One of our sad students is: petkan
Yes.
One of our sad students is: petkan
Yes.
One of our sad students is: borislav
Yes.
One of our sad students is: borislav
Yes.
One of our sad students is: damyan
Yes.
One of our sad students is: damyan
Yes.
One of our sad students is: damyan
Yes.
One of our sad students is: ani
Yes.
One of our sad students is: ani
Yes.
One of our sad students is: ani
Yes.
One of our sad students is: petyr
Yes.
One of our sad students is: petyr

当我将声明更改为:

calculate_sad_moods([]):-!.
calculate_sad_moods([X2|Rest2]) :- 
    write(`One of our sad students is: `),write(X2),nl,
calculate_sad_moods(Rest2).

我最终得到了这个(这不好,因为不是每个人都很难过,但它没有重复记录):

One of our sad students is: ivan
One of our sad students is: dragan
One of our sad students is: petkan
One of our sad students is: borislav
One of our sad students is: damyan
One of our sad students is: ani
One of our sad students is: petyr
One of our sad students is: ivo

我怎样才能只输出悲伤的学生并且只输出一次?我试过添加括号和其他一些技巧,但仍然 - 没有。我没有其他想法可以去哪里看。

PS:这是悲伤声明的样子

[...]
sad(damyan) :- 
    (not(lovesExam(damyan,chemistry)),hasExam(damyan,chemistry));
    (not(lovesExam(damyan,biology),hasExam(damyan,biology)));
    (not(lovesExam(damyan,math),hasExam(damyan,math))).
sad(ani) :- 
    (not(lovesExam(ani,chemistry)),hasExam(ani,chemistry));
    (not(lovesExam(ani,biology),hasExam(ani,biology)));
    (not(lovesExam(ani,math),hasExam(ani,math))).
[...]

它仍然很晦涩,但我仍在学习基础知识...

4

2 回答 2

3

你把切口放在无用的地方。尝试使用 if/then/else 代替 cut,这样会更清晰。

calculate_sad_moods([]).
calculate_sad_moods([X2|Rest2]) :-
    (   sad(X2)
    ->  write('One of our sad students is: '),
        write(X2),
        nl
    ;   true),
    calculate_sad_moods(Rest2).

你有一些错字

...
    (not(lovesExam(damyan,chemistry)),hasExam(damyan,chemistry));
    (not(lovesExam(damyan,biology),hasExam(damyan,biology)));
...

注意第二行应该是

    (not(lovesExam(damyan,biology)),hasExam(damyan,biology));

如果你想收集悲伤的学生,你应该使用 setof/3 。

于 2013-02-20T19:28:22.240 回答
1

我有点不清楚你想用你的谓词实现什么 - 它应该一次打印一个学生并在用户接受时中止,还是应该简单地打印出列表中所有悲伤的学生?这将是两个略有不同的谓词。

至于为什么你会得到重复,我猜你的sad谓词中的某些东西会导致回溯,这意味着它可以被多次评估 - 使用trace序言解释器的功能来找出回溯发生的位置。虽然最好的办法是将sad谓词修复为不回溯,但解决方法是在 the 之后使用 cutsad来防止回溯:

calculate_sad_moods([]):-!.
calculate_sad_moods([X2|Rest2]) :- 
    (sad(X2), !, write(`One of our sad students is: `),
     write(X2), nl, calculate_sad_moods(Rest2));
    calculate_sad_moods(Rest2).

剪切意味着我们需要calculate_sad_moods在编写输出后递归到,因为我们无法再到达or子句的部分(它也被剪切掉了)。

如果您需要在第一个悲伤的学生发现后谓词评估为真的行为,您可以通过;在悲伤情况下的回溯之前使用另一个来实现这一点:

calculate_sad_moods([X2|Rest2]) :- 
    (sad(X2), !, write(`One of our sad students is: `),
    write(X2), (nl; calculate_sad_moods(Rest2))); %only recurse if user says 'no'
    calculate_sad_moods(Rest2).

最后一点,谓词名称非常具有误导性,因为您实际上并没有计算任何东西;也许print_sad_students会是一个更合适的名字。

于 2013-02-20T19:26:43.883 回答