Prolog permutation-code slightly unclear - prolog

I just have a little question about the following code I've just written.
permu([],[]).
permu([H|T],R) :- same_length([H|T],R), select(H,R,Rz), permu(T,Rz).
Result: gives out all permutation (doesn't delete redundancies, but that's not the matter; by using findall and defining another predicate I can fix that easily)
My initial code:
permu([],[]).
permu([H|T],R) :- select(H,R,Rz), permu(T,Rz).
Result: gives out the first result and ends up in endless loop, when clicking "Next". But when I decided to precisely define their length (with same_length as shown above) it suddenly worked.
I have already traced both codes, but I still don't understand why the length of both lists HAS to be defined under any circumstances.
Looking at my initial code, both lists lose one element in each step of the recursion. The list on the left gets its head cut off each run and my R variable is being shortened because of select. The recursion process ends, when both lists run out of elements in the same recursion run => due to select, both lists need to share the same number and type of elements.
What does prevent Prolog from realizing it? What makes him fall into the endless loop?
Taking this code as an example I don't have to define the length but it still works:
permu([], []).
permu([H|T], R) :- permu(T, Rz), select(H, R, Rz).
In contrast to my initial code here the select is just put after the recursion call (permu).

Related

Returning List of possible answers

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!

Member in combination with recursion

I learn Prolog at university and keep stumbling on someting rather odd during the home excercises. I wrote following Prolog clauses, which are part of a much bigger program:
edges(X,Edges):-
findall(Edge,(highway(X,Y,Edge);highway(Y,X,Edge)),Edges).
edgesList([],_).
edgesList([node(X)|InL],OutL):-
member((node(X),Edges),OutL),
edges(X,Edges),
edgesList(InL,OutL).
Which use following facts:
highway(1,2,yellow).
highway(2,3,blue).
highway(1,3,yellow).
You can see highway as a fact that describes two nodes in the first two arguments and an edge in the third. All facts together form a connected graph.
With the clause edgesList, I want to list the edges per node e.g.
Result = [(node(1),[yellow,yellow]),(node(2),[blue,yellow]),(node(3),[blue,yellow])]
But when I write my query:
edgesList([node(1),node(2),node(3)],List).
I get following result:
List = [(node(1),[yellow, yellow]), (node(2),[blue, yellow]), (node(3),[blue, yellow])|_G610]
For some reason, Prolog won't unify the tail of the result-list with the empty list, despite the fact that the member-predicate is used correct, I assume. It's something that happend a few times now in different excercises and it would be good to know what I did wrong...
The problem is in the clause:
edgesList([],_).
because in the end it will fill the list with an uninstantiated tail (|_G610).
One solution is :
edges(X,Edges):-
findall(Edge,(highway(X,Y,Edge);highway(Y,X,Edge)),Edges).
edgesList([],[]).
edgesList([node(X)|InL],[(node(X),Edges)|T]):-
edges(X,Edges),
edgesList(InL,T).

Find adjacent members

I have to find if two members of a list are adjacent. The restriction is to use the append/3 predicate. So far I've done the below, it works if it's true, otherwise I get no answer, it's like it runs eternally.
adjacent(X,Y,L):-
append(L1,[X,Y],T1),append(T1,T2,L).
To see that your program will loop, it suffices to consider the following failure-slice:
adjacent(X,Y,L):-
append(L1,[X,Y],T1), false,
append(T1,T2,L).
If this program will loop, then the original program will loop too. It might succeed, but still it will loop.
In your first goal both L1 and T1 are uninstantiated variables - that's easy to see, because they are not used anywhere else in this fragment. As a consequence, this program will always loop, no matter what X, Y or L might be. To fix this, you have to modify something in the visible part.
One possibility would be to exchange the two goals. But there is an even easier way out:
adjacent(X,Y,L) :-
append(_,[X,Y|_],L)
Note however, that this does not ensure that L is really a well formed list. In fact, adjacent(1,2,[1,2|nonlist]) succeeds. In case it should be a list:
adjacent(X,Y,L) :-
append(_,[X,Y|R],L),
append(R,[],R).
See failure-slice for more.
This might not be the best answer, but you can also try:
adjacent(X,Y,Zs):- append(As,[X,Y|Ys],Zs).
For example:
3 ?- adjacent(1,2,[1,2,3]).
true .
1 ?- adjacent(1,3,[1,2,3]).
false.

Why doesn't the following function work for recursive appending to a list in swi prolog?

I have a list L and I need to split each element into a separate list and again append them together. This is the code I made for the same.
split([],[]).
split([H|T],Ls):-split(T,Ls),splist(H,[]).
make(Val,[H1|List],[H1|Res]):- make(Val,List,Res). make(Val, List,[Val|List]).
splist(H,L2):- make(Sum,[],L1),append(L1,L2,NewL).
When I use this code, each element of L is passed recursively from split() to splist() and made into a list L1 with single element by make(). I need append to keep concatenating L1 and L2. But it does not so so
For example, I have L=[1,2,3]. Now I need the following process to be done.
H=1, L1=[1] and L2=[1]. Next H=2, L1=[2] and L2=[1,2]. Next H=3, L1=[3] and L2=[1,2,3].
I need the output as mentioned above, but this is what my code does.
H=1, L1=[1], and L2= [1]. Next H=2, L1=[2] and L2=[2]. Next H=3, L1=[3] and L2=[3].
I can't make any sense out of your code. make definition is incomplete. As is, it does nothing and then fails.
Your split is equivalent to split(X,[]):- reverse(X,R), maplist(spl([]),R). with spl(B,A):-splist(A,B)., i.e. it tries splist(H,[]) for each element H of the input list X, backwards, to see whether it fails or not - that's its only outcome, as the arguments are fixed - H and [].
naming your predicates split and splist is a very bad idea - we humans are wired to distinguish words from their start, and the only different letter in these names is hidden way far near the end. IOW the two names are very similar, and it is very easy to misread and mistype them.
lastly, for splist(H,L2):- make(Sum,[],L1),append(L1,L2,NewL)., since make cn only fail, so will splist. But even if make were to produce something in L1 out of thin air - Sum starts out uninstantiated mind you - what does it say about L2? That it can be appended to the list L1? Any list can be appended to any other, saying that is saying nothing.
?? :)

Declarative interpretation of list concatenation program in Prolog

I have this very simple problem: write a Prolog program that implement the append Prolog function, that concatenate two strings and that work in the following way:
append([a,b],[c,d],X). ---> X = [a,b,c,d]
append([a,b],X,[a,b,c,d]). ---> X = [c,d]
append([a,b],[X,d],[a,b,c,d]). ---> X=c
append(X,Y,[a,b,c,d]). ---> X=[] and Y=[a,b,c,d)
So I have the following two solutions and I am not so sure if my declarative interpretation is correct:
1) SOLUTION 1:
myappend1([],L,L).
myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3).
I think that I can read it in a declarative way as following:
The fact say that: if the first list (L1) is empty and the second list (L2) is not empty then it is TRUE that the concatenation of L1*L2 is L2
If the fact it is not true it means that the first list is not empty and so the concatenation of the first list and the second list it is not true that is the second list
So, let me call the first list L1, the second list L2 and the third list L3 then the rule responds TRUE if L3 is the concatenation of L1 and L2, false otherwise
I think that the declarative meaning of this rule is that: the head of the rule is true if the body of the rule is true.
In the head extract the first X element from the L1 list and from L3 list (and try to unify, if it matching go ahead, otherwise it means that the third list it is not the concatenation for the first and the second list)
In the body call the function on the first list without X element, the second list and the L3 list (that represent the concatenation)
When it reach the base case in which I have the demonstrated fact myappend1([],L,L). that is true, the program do backtracking at the previous past and because the X element of the first list unified with the X element of the third list it can do that also this computational pass it is TRUE and go back until reach the first assertion
Is this a correct declarative interpretation?
2) SECOND SOLUTION:
myappend2([],L,L).
myappend2(L1,L2,L3) :- L1=[X|T], % Dimostra questo predicato AND
L3=[X|L4], % Dimostra questo predicato AND
myappend2(T,L2,L4). % Dimostra questa funzione
As in the previous solution the fact simply say that: if the first list (L1) is empty and the second list (L2) is not empty then it is TRUE that the concatenation of L1*L2 is L2
If the fact it is not true it means that the first list is not empty and so the concatenation of the first list and the second list it is not true that is the second list
If the fact it is not true Prolog call the rule and this rule means that: the head of the rule is true if the body of the rule is true.
In this case I can read it in this way:
The concatenation of L1 and L2 is L3 is TRUE if it is true that:
The current first X element of L1 unifies with the current first element of concatenation list and myappend2 called on the first sublist, L2 and the third sublist it is true
Is it correct?
for me it is so difficult reasoning in declarative way :-(
Like last time, you're adding restrictions that aren't present in the code. Don't feel bad about it, Prolog is very different and it will take time to get used to it.
Let's start.
append([], L, L).
You said:
If the first list (L1) is empty and the second list (L2) is not empty then it is TRUE that the concatenation of L1*L2 is L2
In fact this rule says nothing about whether L2 is empty--or even a list!--or not. It simply says that the empty list appended to something else is that something else. Observe:
?- append([], foo, X).
X = foo.
The declarative reading here is "the empty list appended to L is L."
If the fact it is not true it means that the first list is not empty and so the concatenation of the first list and the second list it is not true that is the second list
Yes, this is correct, but Prolog isn't probing that deeply into the body. It just says "the first list is not empty, so this rule does not match; moving on."
The next rule:
myappend1([X|L1], L2, [X|L3]) :- myappend1(L1,L2,L3).
Your commentary seems excessively complex to me. I would say that this rule says: "myappend1 of the list [X followed by L1] to L2 is the list [X followed by L3], if myappend1 of the list L1 to L2 is L3." The consequences of this reading, however, are exactly as you describe.
Your understanding of what is happening in the first version is, therefore, correct.
The second solution is, mechanically, exactly the same as the first solution. The only difference is that we have moved the unification from the head of the clause into the body. This version is, to my eyes, clearly inferior, because all it has done is create extra work for the reader.
I think the problem you're having, so far, is that your declarative reasoning is intimately tied up with Prolog's engine of computation. A purer declarative reading like the ones I have supplied are simpler and look more like what the Prolog is saying (and have less to do with how it is evaluated).
It will take practice for you to separate these notions, but I think it will help you get better (clearly it's something you're concerned about). In the meantime there's nothing wrong with coming here and asking for help like you've been doing when you get confused. :)
Let me know if I can help more!
When you try to figure out the declarative meaning of a predicate, you are asking: For which solutions does this predicate hold?
Prolog's1 clauses contribute to the set of solutions independently. So making any connections between the clauses needs some extra scrutiny. It is very easy to make some assumptions that are not the case:
myappend1([],L,L).
If the fact it is not true it means that the first list is not empty and so ...
Consider a goal, myappend1([],[],[a]). The fact does not apply, still the first list is empty. Here, you are attempting to operationalize the meaning of the clause. It is very tempting to do this since the largest part of programming languages can only be understood by imagining how something happens step-by-step. The difficulty in Prolog lies in trying to ignore such details, without entirely ignoring procedural aspects.
myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3).
To read rules, in particular recursive rules, it is helpful to look at the :- which is a 1970s rendering of ← . So it is an arrow, but it goes from right-to-left. Therefore, you can read this rules as follows, starting with the right-hand-side:
Provided that myappend(L1,L2,L3) holds, now cross the :- over to the left side also myappend([X|L1],L2,[X|L3]) holds.
Sometimes, an even better way to read such a rule is to cover the head completely and ask
??? :- myappend1(L1,L2,L3).
Assume, I know some L1, L2, L3 that hold for myappend1(L1,L2,L3). what can I conclude out of this? Is there anything interesting? Is there anything related I can construct easily out of those 3 values?
This is something which is in the beginning a bit revolting, because you might say: But how do I know that such exists? Well, you don't. You are only assuming it exists. If it will never exist, then you will never be able to make that conclusion.
Many try to read the rules left-to-right, but while Prolog is actually executing them left-to-right, the meaning they cover is easier to understand going in the direction of the conclusion. When Prolog executes a rule left-to-right it does not know if this will work out or not. So the execution might be of entirely speculative nature. Think of append(L1,[z],[a,b,c,d,e]). Here, Prolog will apply this rule for each element of the list. But all such application is in vain. That is, ultimately it will fail.
Fine print
1 Actually, the pure, monotonic subset of Prolog.

Resources