Returning List of possible answers - prolog

I have an assignment to make a "simple" chatbot and my main problem now is in a predicate that receives a list of atoms (Ex: ["good","morning"]) and should return a list of possible answers that are already defined in structures. Also the predicate needs to filter for keywords and only return answer that contain keywords from the list given.
I have tried checking if an element from the list is already defined in any of the defined answers. If yes it would concat to the returning list.
(This concat predicate was defined by the teacher and its basically the append/3 already defined).
ans("Hello there", 0).
ans("Hello",0).
ans("Hi",0).
ans("Good Morning",0).
ans("Good Afternoon",0).
ans("Good Night",0).
answer([], List).
answer([H|T], List):- ans(H, _), concat(List, H, List), answer([T], List).
When I run this with answer(["good"],List) and it runs to a infinite (I assume its a infinite loop because it takes a long time to run and give me an error saying that there no space left in stack)
In this case the output should be ["Good Morning", "Good Afternoon", "Good Night"].
I appreciate all the help I can get.

We've got a lot of issues here, starting with your question.
Without concat/3 and how you are calling your code, it really isn't possible for anyone to solve your problems. None of your predicates take a single argument, but you are saying the code goes into an infinite loop if you call it with one. So the best we can do is speculate until you improve your question with the missing detail.
Here's my speculated assumptions: concat/3 is probably append/3. You are calling answer(["good"], Ans).
Looking at your code, concat(List, H, List) looks very wrong to me, for two reasons:
You are trying to mutate List, which is not possible in Prolog (variables cannot change once bound).
You are supplying a non-list in H to be concatenated to List.
Another problem is that List never receives an initial binding, so most likely you have to call this predicate with an argument of [], which means you are treating it as both an input and an output value.
I think your intuition is on the right track here: it should be possible for you to find things by prefix using append/3. Unfortunately, SWI-Prolog does not store strings as lists any more, so there is another predicate you have to use: string_concat/3.
I don't think you can get the return value you want here easily. I think you need to use findall/3 or one of its friends to get multiple solutions, and if you are supplying a list of possible prefixes, you are going to get a list of lists of possible solutions. Perhaps I'm missing something obvious here. Anyway, this is the solution I found:
answer([], []).
answer([H|T], [Answers|R]) :-
findall(Answer,
(ans(Answer, _), string_concat(H, _, Answer)),
Answers),
answer(T, R).
This gives me the following output:
?- answer(["Good"], L).
L = [["Good Morning", "Good Afternoon", "Good Night"]].
Please correct your question so we can be more helpful to you!

Related

Prolog subBag(x, y) tests whether x, considered as a bag, is a subbag of y

I currently working on some prolog problems, one is "subBag(x, y) tests whether x, considered as a bag, is a subbag of y". My code doesn't work at all and always true. Here is my code.
delete(X,[],[]).
delete(X,[X|T],T).
delete(X,[H|T],[H|Result]):-
delete(X,T,Result).
subBag([],[]).
subBag([],[H|T]).
subBag([X|S],[H|T]):-
member(X,[H|T]),
delete(X,[H|T],Result),
subBag(S,Result).
Thank you.
What is a subbag? I take that to mean, all the items in the subbag are present in at least the same quantities as they are in the containing bag. To state it inductively, let's break it into two cases: the case where I have an empty list. Is that a subbag? Yes, of any list:
subbag([], Bag) :- is_list(Bag).
Now, the inductive case. Let's break the subbag into an item and the rest of the subbag. If this item can be removed from the containing bag, and the rest form a subbag of the remainder from the containing bag, then we have a subbag. Like so:
subbag([X|Subbag], Bag) :-
select(X, Bag, RemainingBag),
subbag(Subbag, RemainingBag).
The magic predicate select/3 is a hugely useful utility here, allowing you in one statement to say X is in Bag, and the rest of the bag is in RemainingBag. This kind of situation seems to come up all the time in processing lists in Prolog. (Note that in the SWI Prolog documentation, there is often a little orange :- icon next to the name, which will take you to the source code for that predicate, in case you've been given a stupid requirement not to use a built-in predicate by a clueless professor.)
I want to warn you that the efficiency of this solution is not great, but I actually think the nature of this problem might just be that way. The number of solutions you'll obtain from an query (like subbag(X, [1,2,3,4,5])) is going to be large; I found it to be essentially the number of permutations of a set, using the OEIS (sequence A000522).
I dont understand completely how your code should work, but i think that there is for sure too much splitting into head and tail in places where it is not necessary.
Maybe this predicate will help you to solve your problem.
isSublist(Sublist,List) :-
append([_,Sublist,_],List).
This predicate uses append/2 build-in predicate, read about it here

In Prolog how can I cut redundant answers

I am working on a dictionary-like program with prolog, and my code goes like this:
define(car,vehicle).
define(car,that).
define(car,has).
define(car,four).
define(car,wheels).
define(wheels,round).
define(wheels,object).
define(wheels,used).
define(wheels,in).
define(wheels,transportation).
defined(X):-define(X,_).
anotherdefined(X):- \+ undefined(X).
undefined(X):- \+define(X,_).
I am trying to write a defined/1 predicate which will give me:
?-defined(X).
X = car ;
X = wheels ;
false.
Yet, my defined/1 gives me X=car. five times (naturally) for everytime it counters define(car,_).
and my anotherdefined/1 gives me only true. What is the method to stop prolog backtracking to the other instances of define(car,_).,and skip to define(wheels,_).?
Edit: I have written the following lines to get the result I want with givedefinedword/1,
listdefined(X):-findall(Y,defined(Y),Z),sort(Z,X).
givedefinedword(X):-listdefined(List),member(X,List).
However since I wanted an efficient predicate (which I will use in many others) it beats the purpose. This predicate does too much process.
Or, Would it be better to use a predicate that modifies the code? say prepares a list of defined words, and modifies it when new definitions are added.
Thanks.
If you change define to relate items and lists, like
definelist(car, [vehicle, that, has, four, wheels]).
% etc.
defined(X) :- definelist(X, _).
then defined will no longer produce duplicates, nor require linear space.
Of course, a query define(X, Y) must now be performed as definelist(X, L), member(Y, L). If you want this to be efficient as well, you may need to duplicate all definitions.
What are you trying to achieve with your program? It seems that you want to have facts in the form:
"A car is a vehicle that has four wheels"
"Wheels are round objects used in transportation" (a bit vague)
How are you going to use these facts? #larsmans suggestion if perfectly fine, if you want to just have your statement as a "sentence". It really depends what you will do with the information though.
Consider structuring the information in your database:
is(car, vehicle).
is(bicycle, vehicle).
is(boat, vehicle).
has(car, wheel(four)).
has(car, motor).
has(bicycle, wheel(two)).
Given this database, you can at least ask a question like, "what vehicles are there?", "does a bicycle have a motor?", or maybe, "how many wheels does a car have?", or "which vehicles have no wheels?"
?- is(X, vehicle).
?- has(bicycle, motor).
?- has(car, wheel(N)).
?- is(X, vehicle), \+ has(X, wheel(_)).
and so on.
Once you have defined your problem better, you can define your data structures better, which will make writing a program to solve your problem easier.

Prolog list membership, multiple results returned

I have a standard procedure for determining membership of a list:
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
What I don't understand is why when I pose the following query:
?- member(a,[a,b]).
The result is
True;
False.
I would have thought that on satisfying the goal using the first rule (as a is the head of the list) True would be returned and that would be the end of if. It seems as if it is then attempting to satisfy the goal using the second rule and failing?
Prolog interpreter is SWI-Prolog.
Let's consider a similar query first: [Edit: Do this without adding your own definition ; member/2 is already defined]
?- member(a,[b,a]).
true.
In this case you get the optimal answer: There is exactly one solution. But when exchanging the elements in the list we get:
?- member(a,[a,b]).
true
; false.
Logically, both are just the affirmation that the query is true.
The reason for the difference is that in the second query the answer true is given immediately upon finding a as element of the list. The remaining list [b] does not contain a fitting element, but this is not yet examined. Only upon request (hitting SPACE or ;) the rest of the list is tried with the result that there is no further solution.
Essentially, this little difference gives you a hint when a computation is completely finished and when there is still some work to do. For simple queries this does not make a difference, but in more complex queries these open alternatives (choicepoints) may accumulate and use up memory.
Older toplevels always asked if you want to see a further solution, even if there was none.
Edit:
The ability to avoid asking for the next answer, if there is none, is extremely dependent on the very implementation details. Even within the same system, and the same program loaded you might get different results. In this case, however, I was using SWI's built-in definition for member/2 whereas you used your own definition, which overwrites the built-in definition.
SWI uses the following definition as built-in which is logically equivalent to yours but makes avoiding unnecessary choice points easier to SWI — but many other systems cannot profit from this:
member(B, [C|A]) :-
member_(A, B, C).
member_(_, A, A).
member_([C|A], B, _) :-
member_(A, B, C).
To make things even more complex: Many Prologs have a different toplevel that does never ask for further answers when the query does not contain a variable. So in those systems (like YAP) you get a wrong impression.
Try the following query to see this:
?- member(X,[1]).
X = 1.
SWI is again able to determine that this is the only answer. But YAP, e.g., is not.
Are you using the ";" operator after the first result then pushing return? I believe this is asking the query to look for more results and as there are none it is coming up as false.
Do you know about Prolog's cut - !?
If you change member(X, [X|_]). to member(X, [X|_]) :- !. Prolog will not try to find another solution after the first one.

Uses of non-ground facts in Prolog?

In Prolog you can write a ground fact as:
lost(jen).
You can also write a non-ground fact as:
lost(X).
Does this makes any sense? Could you show me a practical/real example where non ground facts are used?
Thanks,
Another case, avoiding lists, is where most cases are "true" and you just want to exclude some few cases that are false. So you deliberately fail thoses cases, then let everything else pass through.
Then you can do, say...
inhabited(antarctica) :- !, fail.
% all the other continents are inhabited
inhabited(_).
Well, you can have other things in facts besides atoms, for example you can have lists. Once you've done that, you may want to know about a one-element list, and you can have
oneelement([X]).
Likewise, say you want to compare what is the last element in a list
lastelement([X],X).
lastelement([_|Remainder],X) :- lastelement(Remainder,X).
The very useful member predicate is defined as
member([X|_],X).
member([_|Remainder],X) :- member(Remainder,X).
Each of these uses a non-ground fact as its base case, by matching a special form that's more specific than just lost(X)

Simple graph search in Prolog

I'm trying to code a simple graph search in SWI-Prolog. I came up with the following program:
adjacent(1,4). adjacent(4,2). adjacent(3,6).
adjacent(6,4). adjacent(7,10). adjacent(4,9).
adjacent(5,10). adjacent(7,10). adjacent(7,12).
adjacent(6, 11). adjacent(13,11). adjacent(9,14).
adjacent(14,12). adjacent(10,15). adjacent(9,12).
connected(X,Y) :- adjacent(X,Y); adjacent(Y,X).
path(A,B,[A|B]) :-
connected(A,B).
path(A,B,[A|R]) :-
\+member(R,A),
connected(A,C),
A \== C,
path(C,B,R).
But this program causes a stack overflow. What am I doing wrong and how can it be fixed?
You are trying to use the returned path also as a check for avoiding loops. That won't work when searching for a path because the path is not yet instantiated at the negation.
The simplest solution is to add another input argument where you collect the nodes already visited and check these to avoid repetition.
Also, I think you should check A \== B instead of A \== C. You don't have loops on nodes, so the latter will never happen. The case A == B is handled in the first clause, so you don't want to do that again in the second clause.
You also got the arguments of member backwards and need to fix the list in the first clause, as Martin has written.
An advanced way to avoid infinite loops without an extra argument is to use freeze/2 on the negation.
Also take a look at how debugging works in Prolog, that might help you understand things better.
The main problem here is the member test: the signature is member(Element,List); you seem to assume that the arguments are the other way 'round.
In addition, your first path predicate is meant to test a two-element list, however, B really unifies with the rest list (which then isn't connected).
If you fix these, you find that this can only work for fully instantiated variables, as the negation doesn't work well for unbound variables.

Resources