I am writing a Prolog predicate that cuts first three elements off a numbered list and prints the result. An example of a numbered list:
[e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)].
The original predicate for normal list looks like this:
strim([H|T],R) :-
append(P,R,[H|T]),
length(P,3).
So, since length predicate works perfectly for numbered lists as well, I only had to write predicate that appends one numbered list to another:
compose([],L,[L]).
compose([e(F,C)|T],e(A,_),[e(F,C)|L]) :-
N is C+1,
compose(T,e(A,N),L).
napp(X,[],X).
napp(L,[e(X,Y)|T],M):-
compose(L,e(X,Y),L1),
napp(L1,T,M).
I expected the predicate for numbered list to be a slightly modified version of predicate for normal list, so I wrote this:
numstrim([e(X,Y)|T],R) :-
napp(P,R,[e(X,Y)|T]),
length(P,3).
However, I'm getting this error:
ERROR: compose/3: Arguments are not sufficiently instantiated
Could somebody please explain what's causing the error and how to avoid it? I'm new to Prolog.
Instantiation errors are a common phenomenon in Prolog programs that use moded predicates: These are predicates that can only be used in special circumstances, requiring for example that some arguments are fully instantiated etc.
As a beginner, you are in my view well advised to use more general predicates instead, so that you can freely exchange the order of goals and do not have to take procedural limitations into account, at least not so early, and without the ability to freely experiment with your code.
For example, in your case, the following trivial change to compose/3 gives you a predicate that works in all directions:
compose([], L, [L]).
compose([e(F,C)|T], e(A,_), [e(F,C)|L]) :-
N #= C+1,
compose(T, e(A,N), L).
Here, I have simply replaced the moded predicate (is)/2 with the CLP(FD) constraint (#=)/2, which completeley subsumes the more low-level predicate over integers.
After this small change (depending on your Prolog system, you may have to import a library to use the more general arithmetic predicates), we get:
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es).
nontermination
So, we find out that the instantiation error has actually overshadowed a different problem that can only be understood procedurally, and which has now come to light.
To improve this, I now turn around the two goals of numstrim/2:
numstrim([e(X,Y)|T], R) :-
length(P, 3),
napp(P, R, [e(X,Y)|T]).
This is because length(P, 3) always terminates, and placing a goal that always terminates first can at most improve, never worsen, the termination properties of a pure and monotonic logic program.
So now we get:
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es).
Es = [e(b, _1442), e(a, _2678), e(r, _4286)] .
That is, at least we get an answer now!
However, the predicate still does not terminate universally, because we get:
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es), false.
nontermination
I leave fixing this as an exercise.
Related
I'm new to prolog and I've been having trouble with some homework.
On some part of my code I have to generate subsets of a given set on backtracking. Meaning, the code should try for a subset, and when it fails the next condition, try the next subset. I have done some research and the default function subset won't backtrack because as explained in this question both arguments are input arguments. So I built a custom one, which still isn't backtracking. Can you give me a hint on what I'm failing on? Here's my code:
numNutrients(8).
product(milk,[2,4,6]).
product(porkChops,[1,8]).
product(yoghurt,[3,1]).
product(honey,[5,7]).
product(plastic,[3,5,2]).
product(magic,[5,7,8]).
nutrientlist(N,L):-findall(I,between(1,N,I),L).
subset2([],[]):-!.
subset2([X|T],[X|T2]):-
subset2(T,T2).
subset2([_|T],[T2]):-
subset2(T,T2).
shopping(K,L):-
numNutrients(J),
nutrientlist(J,N),
findall(P,product(P,_),Z),
subset2(X,Z),
length(X,T),
T =< K,
covers(X,N),
L = X.
covers(_,[]):-!.
covers([X|L],N):-
product(X,M),
subset2(M,N),
subtract(N,M,T),
covers(L,T).
main:-
shopping(5,L),
write(L).
The problem is on predicate shopping(K,L). When it gets to predicate subset2, it gives the whole set, which has length 6 (not 5), then fails and doesn't backtrack. Since all previous predicates can't backtrack it just fails.
So, why doesn't subset2 backtrack?
Thank you for your time.
Primary focus: subset2/2
First, let us focus only on the predicate that shows different properties from those you expect.
In your case, this is only subset2/2, defined by you as:
subset2([], []) :- !.
subset2([X|T], [X|T2]) :-
subset2(T, T2).
subset2([_|T], [T2]) :-
subset2(T, T2).
I will now use declarative debugging to locate the cause of the problem.
For this method to apply, I remove the !/0, because declarative debugging works best on pure and monotonic logic programs. See logical-purity for more information. Thus, we shall work on:
subset2([], []).
subset2([X|T], [X|T2]) :-
subset2(T, T2).
subset2([_|T], [T2]) :-
subset2(T, T2).
Test cases
Let us first construct a test case that yields unintended answers. For example:
?- subset2([a], [a,b]).
false.
That obviously not intended. Can we generalize the test case? Yes:
?- subset2([a], [a,b|_]).
false.
So, we have now an infinite family of examples that yield wrong results.
Exercise: Are there also cases where the program is too general, i.e., test cases that succeed although they should fail?
Locating mistakes
Why have we seen unintended failure in the cases above? To locate these mistakes, let us generalize the program.
For example:
subset2(_, []).
subset2([_|T], [_|T2]) :-
subset2(T, T2).
subset2(_, [T2]) :-
subset2(T, T2).
Even with this massive generalization, we still have:
?- subset2([a], [a,b|_]).
false.
That is, we have many cases where we expect the query to succeed, but it fails. This means that the remaining program, even though it is a massive generalization of the original program, is still too specific.
Correcting the program
To make the shown cases succeed, we have to either:
add clauses that describe the cases we need
or change the existing clauses to cover these cases too.
For example, a way out would be to add the following clause to the database:
subset2([a], [a,b|_]).
We could even generalize it to:
subset2([a], [a|_]).
Adding either or both of these clauses to the program would make the query succeed:
?- subset2([a], [a,b|_]).
true.
However, that is of course not the general definition of subset2/2 we are looking for, since it would for example still fail in cases like:
?- subset2([x], [x,y|_]).
false.
Therefore, let us go with the other option, and correct the existing definition. In particular, let us consider the last clause of the generalized program:
subset2(_, [T2]) :-
subset2(T, T2).
Note that this only holds if the second argument is a list with exactly one element which is subject to further constraints. This seems way too specific!
Therefore, I recommend you start by changing this clause so that it at least makes the test cases collected so far all succeed. Then, add the necessary specializations to make it succeed precisely for the intended cases.
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.
Having recently got into Prolog I've been using it for a few simple tasks and began to wonder about using member within forall loops like the one in the trivial example below:
forall(member(A,[1,2,3,4]), print(A)).
In the case that you do something like this is it always true that forall will process the elements within the list in the same order every time its called? Does it have to be enforced by say doing something like:
A = [1,2,3,4], sort(A, B), forall(member(C,B), print(C)).
From what little research I've initially done I'm guessing that it comes down to the behaviour of member/2 but the documentation for the function on SWI-Prolog's website is very brief. It does however mention determinism with regards member/2 which gave me an inkling I might be on the right path in saying that it would always extract the elements in the same order, though I'm far from certain.
Can anyone give me any guarantees or explanations on this one?
Non-determinism in Prolog simply refers to a predicate having potentially more than one solution. Clearly, member/2 is such a predicate. This does not mean that you have to be worried about your computation becoming unpredictable. Prolog has a well-defined computation rule which essentially says that alternative solutions are explored in a depth-first, left-to-right manner. Thus your goal member(X,[1,2,3,4]) will generate solutions to X in the expected order 1,2,3,4.
Sorting the list [1,2,3,4] will not make any difference, as it is already sorted (according to Prolog's standard term order).
A word of caution about forall/2: some Prologs define this, but it is probably less useful than you imagine, because it is not really a "loop". You can use it in your example because you only perform a print side effect in each iteration. For most other purposes, you should familiarize yourself with recursive patterns like
print_list([]).
print_list([X|Xs]) :- print(X), print_list(Xs).
Strictly speaking, there is no guarantee in SWI on several levels:
1mo, that member/2 or forall/2 will perform in exactly this manner, since you can redefine them.
?- [user].
member(X,X).
|: % user://1 compiled 0.00 sec, 2 clauses
true.
?- forall(member(A,[1,2,3,4]), print(A)).
[1,2,3,4]
true.
However, member/2 is defined in the Prolog prologue which covers all the details you are interested in.
As for forall(A,B) it is safer to write \+ (A, \+B) instead, since this relies on standard features only. There is no definition of forall/2 as such, so it is difficult to tell what is the "right" behavior.
2do, that SWI will be standard conforming. If you read the documentation, you will note that there is no self-declaration (as for, e.g. SICStus Prolog) for standard conformance. In fact, \+ (A, \+B) is not fully conforming, as in the following example that should silently fail, but rather prints nonconforming
?- \+ ( C= !, \+ (C,fail;writeq(nonconforming))).
N208 has forall/2 defined + (call(Generator), + call(Test)), so this makes it less dubious. But by virtue that the ISO core standard (+)/1 does already a call/1 and that the ISO core standard (,)/2 will be subject to body conversion one can simply define it as follows in an ISO core standard Prolog:
forall(Generator, Test) :-
\+ (Generator, \+ Test).
SWI-Prolog has also implemented this way, and the error observed by Ulrich Neumerkel will not be seen when using forall/2:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.18)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- \+ ( C= !, \+ (C,fail;writeq(nonconforming))).
nonconforming
true.
?- forall(C=!, (C,fail;writeq(nonconforming))).
false.
Side remark:
I don't know how useful it is for loop. It seems to me using it for loops is not the right approach, since the test might fail, and then the construct also fails. I have also seen by Striegnitz and Blackburn the following definition of a helper predicate that they call failiure driven loop.
doall(Goal) :-
Goal, fail.
doall(_).
I find myself directly writing Goal, fail; true which also does the job:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.18)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- member(A,[1,2,3,4]), write(A), nl, fail; true.
1
2
3
4
true.
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 have a database of facts like this:
li(a,2).
li(b,3).
li(b,1).
li(c,2).
li(d,1).
li(d,1).
I need to write a predicate more(+Let) that succeeds if it exists more than one fact li(Let,_).
For example the queries more(b) and more(d) will succeed, but more(a) and more(c) will not.
My idea was to check if li(Let,_) succeeds more than once, but I do not know how to do it.
Try findall/3:
findall(X, li(d,X), L), length(L,N), N>1.
Abstracting the d out and making a predicate is trivial. Right? :)
If you don't want to use any of the predicates like findall, you can change the representation of your knowledge - bring it down one level, so to speak:
my_knowledge(li, [a-2,b-3,b-1,c-2,d-1,d-1]).
and then you can use SWI Prolog's predicate select/3 to handle it:
select_knowledge(kn, key, R):-
my_knowledge(kn,L),
select_key(L,key,R).
select_key(L,K,R):-
select(K-X,L,L1) -> R=[X|R1], select_key(L1,K,R1)
; R = [].
You can rewrite the last predicate as basic recursion over lists, and then tweak it to stop after getting first N results.
more_than_once(Goal) :-
\+ \+ call_nth(Goal,2).
With call_nth/2 as defined in this answer.
The big advantage of this solution compared to the other solutions proposed is that it will succeed rapidly even if there is a very large sequence of answers. In fact, it will even succeed for an infinite sequence of answers:
?- more_than_once(repeat).
true.
?- more_than_once(between(1,100000,_)).
true.
(The implementation of call_nth/2 uses some non-standard, low-level built-ins of SWI. It is possible to avoid that, but with even more headache.)
SWI-Prolog has library(aggregate).
:- [library(aggregate)].
more(Key) :- aggregate_all(count, li(Key, _), C), C > 1.
test:
?- more(b).
true.
?- more(a).
false.
It's not very easy to learn, but useful to handle such common tasks. If you have a very large code base, then findall (and aggregate as well, that uses findall inside) could be inefficient, building a list only to count its elements.
Then you could use a side effect based predicate: in this related answer you'll find such utility. For max efficiency, see the comments, where is explained how to use nb_setval/nb_getval...