Reputation: 49
This is my code:
students([], NameList).
students([Name1+Name2+_|MoreProjects], [Name1,Name2|NameList]) :-
not_member(Name1, NameList),
not_member(Name2, NameList),
students(MoreProjects, NameList).
students([Name1+Name2+_|MoreProjects], [Name1|NameList]) :-
not_member(Name1, NameList),
not(not_member(Name2, NameList)),
students(MoreProjects, NameList).
students([Name1+Name2+_|MoreProjects], [Name2|NameList]) :-
not(not_member(Name1, NameList)),
not_member(Name2, NameList),
students(MoreProjects, NameList).
students([Name1+Name2+_|MoreProjects], NameList) :-
not(not_member(Name1, NameList)),
not(not_member(Name2, NameList)),
students(MoreProjects, NameList).
not_member(_, []).
not_member(X, [Head|Tail]) :-
X \= Head,
not_member(X, Tail).
What it's supposed to do is check if Name1 or Name2 is already in the unbound list, and adds it to the result.
Running this legitimate query
students([ Dickens+Joyce+1,
Chekhov+Tolstoy+2,
Austen+Shakespeare+3,
Shirley+Byron+4
],
StudentList).
just gives me false. How should I adjust my coding?
Upvotes: 1
Views: 453
Reputation: 12992
The problem is that you can't test if an element e.g Name1 is member or not in Namelist because Namelist is not instantiated and this leads to problems when using negation. For example try:
?- member(a,L).
L = [a|_G6809] .
It succeeded assuming L is [a|_G6809], so it partially instantiated L, but try now:
?- \+member(a,L).
false.
This can't do anything other that fail. You have used this many times like: not(not_member(Name2, NameList))
which will fail as the example above since NameList is not instantiated.
In order to fix you need another List- accumulator where you will store all the element that you find and it will be fully instantiated at every step so you will be able to check if an element is member or not:
students(L1,L2):-students(L1,L2,[]).
students([], L, L).
students([Name1+Name2+_|MoreProjects], NameList, L):-
not_member(Name1, L),
not_member(Name2, L),
students(MoreProjects, NameList,[Name1,Name2|L]).
students([Name1+Name2+_|MoreProjects], NameList, L):-
not_member(Name1, L),
not(not_member(Name2, L)),
students(MoreProjects, NameList, [Name1|L]).
students([Name1+Name2+_|MoreProjects], NameList, L):-
not(not_member(Name1, L)),
not_member(Name2, L),
students(MoreProjects, NameList, [Name2|L]).
students([Name1+Name2+_|MoreProjects], NameList, L):-
not(not_member(Name1, L)),
not(not_member(Name2, L)),
students(MoreProjects, NameList, L).
not_member(_, []).
not_member(X, [Head|Tail]) :-
X \= Head,
not_member(X, Tail).
In the above we start giving a third parameter as an empty list an add element when necessary.
Also when you try querying
students([ Dickens+Joyce+1,
Chekhov+Tolstoy+2,
Austen+Shakespeare+3,
Shirley+Byron+4
],
StudentList).
note that whatever starts with capitals is a variable in Prolog so you need to query : students([ "Dickens"+"Joyce"+1, "Chekhov"+"Tolstoy"+2, "Austen"+"Shakespeare"+3, "Shirley"+"Byron"+4 ], StudentList). Now let's try test it:
students([ "Dickens"+"Joyce"+1,"Chekhov"+"Tolstoy"+2, "Auste"+"Shakespeare"+3,"Shirley"+"Byron"+4 ], StudentList).
StudentList = ["Shirley", "Byron", "Auste", "Shakespeare", "Chekhov", "Tolstoy", "Dickens", "Joyce"] ;
false.
?- students([ "Dickens"+"Joyce"+1,"Byron"+"Tolstoy"+2, "Byron"+"Shakespeare"+3,"Byron"+"Byron"+4 ], StudentList).
StudentList = ["Shakespeare", "Byron", "Tolstoy", "Dickens", "Joyce"] ;
false.
Upvotes: 1