I have a question I would like to ask you something about a code snippet:
insert_pq(State, [], [State]) :- !.
insert_pq(State, [H|Tail], [State, H|Tail]) :-
precedes(State, H).
insert_pq(State, [H|T], [H|Tnew]) :-
insert_pq(State, T, Tnew).
precedes(X, Y) :- X < Y. % < needs to be defined depending on problem
the function quite clearly adds an item to a priority queue. The problem I have is the cut off operator in the first line. Presumably whenever the call reaches this line of code this is the only possible solution to the query, and the function calls would simply unwind (or is it wind up?), there would be no need to back track and search for another solution to the query.
So this cut off here is superfluous. Am I correct in my deduction?
Yes, any half-decent Prolog compiler will notice that there is no other clause where the second argument is an empty list.
It would be more useful at the end of the second clause, though I'd rather combine the second and the third clause and use a local cut (precedes(...) -> ... ; ...).
The particular technique that the compiler users to eliminate candidate predicates for matching is called argument indexing. Different prolog implementations could potentially index different numbers of arguments by default.
So if you're worried about whether an argument is being indexed or not, you should check how many arguments the prolog you're using indexes. According to the SWI reference manual it only indexes the first argument by default. So in your case the cut is actually not redundant. You can however explicitly stipulate which arguments should be indexed using the predicates index/1 and hash/1 which are linked to in the above link.
Or you could just reorder the arguments, or you could just keep the cut.
Yes, you are correct. Even if the compiler isn't half-decent (which SWI Prolog certainly is), the worst it can do is match the second and third clauses, which will fail immediately.
However, if the second clause matches, the third does as well. Is this the intended behaviour?
Related
I know there is technically no 'return' in Prolog but I did not know how to formulate the question otherwise.
I found some sample code of an algorithm for finding routes between metro stations. It works well, however it is supposed to just print the result so it makes it hard to be extended or to do a findall/3 for example.
% direct routes
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Y,Stations),
append(Output,[[X,Line,Y]],NewOutput),
print(NewOutput).
% needs intermediate stop
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Intermediate,Stations),
X\=Intermediate,Intermediate\=Y,
append(Output,[[X,Line,Intermediate]],NewOutput),
findRoute(Intermediate,Y,[Line|Lines],NewOutput).
line is a predicate with an atom and a list containing the stations.
For ex: line(s1, [first_stop, second_stop, third_stop])
So what I am trying to do is get rid of that print at line 11 and add an extra variable to my rule to store the result for later use. However I failed miserably because no matter what I try it either enters infinite loop or returns false.
Now:
?- findRoute(first_stop, third_stop, [], []).
% prints [[first_stop,s1,third_stop]]
Want:
?- findRoute(first_stop, third_stop, [], R).
% [[first_stop,s1,third_stop]] is stored in R
Like you, I also see this pattern frequently among Prolog beginners, especially if they are using bad books and other material:
solve :-
.... some goals ...
compute(A),
write(A).
Almost every line in the above is problematic, for the following reasons:
"solve" is imperative. This does not make sense in a declarative languague like Prolog, because you can use predicates in several directions.
"compute" is also imperative.
write/1 is a side-effect, and its output is only available on the system terminal. This gives us no easy way to actually test the predicate.
Such patterns should always simply look similar to:
solution(S) :-
condition1(...),
condition2(...),
condition_n(S).
where condition1 etc. are simply pure goals that describe what it means that S is a solution.
When querying
?- solution(S).
then bindings for S will automatically be printed on the toplevel. Let the toplevel do the printing for you!
In your case, there is a straight-forward fix: Simply make NewOutput one of the arguments, and remove the final side-effect:
route(X, Y, Lines, Output, NewOutput) :-
line(Line, Stations),
\+ member(Line, Lines),
member(X, Stations),
member(Y, Stations),
append(Output, [[X,Line,Y]], NewOutput).
Note also that I have changed the name to just route/5, because the predicate makes sense also if the arguments are all already instantiated, which is useful for testing etc.
Moreover, when describing lists, you will often benefit a lot from using dcg notation.
The code will look similar to this:
route(S, S, _) --> []. % case 1: already there
route(S0, S, Lines) --> % case 2: needs intermediate stop
{ line_stations(Line, Stations0),
maplist(dif(Line), Lines),
select(S0, Stations0, Stations),
member(S1, Stations) },
[link(S0,Line,S1)],
route(S1, S, [Line|Lines]).
Conveniently, you can use this to describe the concatenation of lists without needing append/3 so much. I have also made a few other changes to enhance purity and readability, and I leave figuring out the exact differences as an easy exercise.
You call this using the DCG interface predicate phrase/2, using:
?- phrase(route(X,Y,[]), Rs).
where Rs is the found route. Note also that I am using terms of the form link/3 to denote the links of the route. It is good practice to use dedicated terms when the arity is known. Lists are for example good if you do not know beforehand how many elements you need to represent.
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.
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.
I can't come up with a situation where I would need it.
Elegant systems provide false/0 as a declarative synonym for the imperative fail/0. An example where it is useful is when you manually want to force backtracking for side-effects, like:
?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3
Instead of false/0, you can also use any goal that fails, for example a bit shorter:
?- between(1,3,N), format("line ~w\n", [N]), 0=1.
line 1
line 2
line 3
Thus, false/0 is not strictly needed but quite nice.
EDIT: I sometimes see beginners who want to state for example "my relation does not hold for the empty list", and then add:
my_relation([]) :- false.
to their code. This is not necessary, and not a good example of using false/0, except for example in failure slices that are programmatically generated. Instead, concentrate on stating the things that hold about your relation. In this case, just leave out the entire clause, and define the relation only for lists that are not empty, i.e., have at least one element:
my_relation([L|Ls]) :- etc.
or, if you are describing other terms in addition to lists as well, use a constraint like:
my_relation(T) :- dif(T, []), etc.
Given only either (or even both) of these two clauses, the query ?- my_relation([]). will automatically fail. It is not necessary to introduce an additional clause which never succeeds for that purpose.
Explicit failure. fail is often used in conjunction with cut: ... !, fail. to enforce failure.
For all construct. Explicit usage of fail/false to enumerate via backtracking is a very error prone activity. Consider a case:
... ( generator(X), action(X), fail ; true ), ...
The idea is thus to "do" action for all X. But what happens, if action(X) fails? This construct simply continues with the next candidate — as if nothing happened. In this manner certain errors may remain undetected for very long.
For such cases it is better to use \+ ( generator(X), \+ action(X) ) which fails, should action(X) fail for some X. Some systems offer this as a built-in forall/2. Personally, I prefer to use \+ in this case because the \+ is a bit clearer that the construct does not leave a binding.
Failure-slice. For diagnostic purposes it is often useful to add on purpose false into your programs. See failure-slice for more details.
One case (taken from Constraint Logic Programming using Eclipse) is an implementation of not/1:
:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .
If Q succeeds, the cut (!) causes the second not clause to be discarded, and the fail ensures a negative result. If Q fails, then the second not clause fires first.
Another use for fail is to force backtracking through alternatives when using predicates with side effects:
writeall(X) :- member(A,X), write(A), fail.
writeall(_).
Some people might not consider this particularly good programming style though. :)
fail/0 is a special symbol that will immediately fail when prolog encounters it as a goal.
fail is often used in conjunction with CUT(!) to enforce failure.
like(me,X) :- chess(X),!,fail.
like(me,X) :- games(X).
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.