Negation in prolog query is not working - prolog

HI i have a simple knowledge database defined as:
carClass('X1','Oil','small').
carClass('X2','gas','big').
carClass('X3','Petrol','big').
carClass('X4','oil','small').
carClass('X5','Oil','small').
carClass('X6','gas','big').
I am trying to write a rule that will answer the query: Display all carClass that runs on 'oil' and IS NOT 'big'.
I am trying to implement it using:
OnOilButNotBig :-
carClass(CarClass,'oil',_),
carClass(CarClass,'oil', \+('big') ),
write(CarClass).
but this is not working.

You have to understand the difference between a predicate and a functor.
If we oversimplify things a bit, a predicate is an identifier at the top level, so carClass/3 is a predicate, write/1 is a predicate and onOilButNotBig/0 is. You can call a predicate. A predicate with filled in arguments is a goal.
A functor on the other hand is an identifier not on the top level. Constants are functors, variables are functors, and functions with arguments are functors. Examples of functors are 'X1', 'oil' and foo(X,bar,qux(2)).
The negation expects a goal. 'big' in this case is not a goal, in fact \+('big') itself is a functor.
You can only solve this by turning the condition into a goal and ensure you will call it. This can be done like:
onOilButNotBig :-
carClass(CarClass,'oil',_),
carClass(CarClass,'oil',X),
\+(X = 'big'),
write(CarClass).
Furthermore I do not really see why you call carClass/3 twice. An equivalent and slightly more efficient program is the following:
onOilButNotBig :-
carClass(CarClass,'oil',X),
\+(X = 'big'),
write(CarClass).
Finally as #Repeat noted, you need to use names that start with a lowercase for predicates and functions.

First things first!
The code doesn't compile1.
Why? Predicate names usually start with lowercase characters2.
My advice: instead of OnOilButNotBig write onOilButNotBig!
To express term inequality, use the right prolog-dif goal(s), like so:
onOilButNotBig :-
dif(X, big),
carClass(CarClass, oil, _),
carClass(CarClass, oil, X),
write(CarClass).
As a side remark, there are a few more issues with your code:
Use side-effect based I/O only when necessary.
In most cases, it is preferable to use the interactive prolog-toplevel for data input/output!
onOilButNotBig(CarClass) :-
dif(X, big),
carClass(CarClass, oil, _),
carClass(CarClass, oil, X).
For the sake of readability, please do not use atoms like 'oil' and 'Oil'.
Pick one and stick to it! I suggest oil (lowercase) which does not need escaping.
The goal carClass(CarClass, oil, _) is completely redundant.
Why? It is a generalisation of the close-by goal carClass(CarClass,oil,X).
Footnote 1: When using b-prolog 8.1, sicstus-prolog 4.3.2, swi-prolog 7.3.14, and xsb 3.6.
Footnote 2: Names can also starting with uppercase characters if the right (escaping with single-quotes) is utilized.
Footnote 3: In general, redundant goals are ok, but they suggest to me your code will likely not behave as intended.

Related

Defining a predicate as substitute for (=)/2 (Unification) in Prolog

For my programming course's assignment, I have to write some Prolog code without using any pre-defined predicates (excluding , and ;), but saw no way around using =, as I had to check whether a variable A is equal to (can be identified with) some foo(B, C).
Since this isn't allowed though, I'd like to implement my own predicate myUnification/2, which should essentially behave in the same way, but I have no idea how to go about this. I've tried looking at the SWI-Prolog Documentation for assistance but it only explains what the predicate does, not how it actually works internally.
It is right there in the docs :-D
=(Term, Term).
To use 'unify' instead of '=', define:
unify(A, A).
You can now do magic like this:
?- unify(X, foo(a, b)).
X = foo(a, b).

Functional patterns in Prolog

How do I create a predicate that takes another predicate and returns a derived version of it?
For example, pairwise predicates can be fairly mechanically extended to apply to lists:
all_whatever(_, []).
all_whatever(X, [Y|T]) :-
whatever(X, Y),
all_whatever(X, T).
What would be the definition of
pairwise_listwise(whatever, all_whatever).
If it's not possible/common/clunky/violates principles, what would be the alternative pattern?
There are two different ways to achieve what you want. The simplest, and likely preferred, way is to define a meta-predicate that takes any binary predicate and applies it to all elements of the list like so:
listwise(_,_,[]).
listwise(P,Y,[X|Xs]) :-
call(P,Y,X),
listwise(P,Y,Xs).
You can then call this as listwise(whatever, Y1, Xs1) to apply whatever to Y1 and each element of Xs1.
This is made possible thanks to the call/N meta-predicate. Note that this meta-predicate can also take partially constructed goals as first argument, so that an alternative formulation could be:
listwise(_,[]).
listwise(P,[X|Xs]) :-
call(P,X),
listwise(P,Xs).
Which is then called as listwise(whatever(Y1),Xs1). This version of the predicate is actually known as maplist/2 instead of listwise, at least in SWI-Prolog (in module library(apply)) and SICStus Prolog (in module library(lists)).
The second way to achieve what you want (actually closer to what you where asking for) is to actually define a new predicate all_whatever/2 using term expansion. Term expansion is a mechanism to rewrite terms when they are loaded (see e.g. for more details in SWI-Prolog: https://www.swi-prolog.org/pldoc/doc_for?object=term_expansion/2). I am showing here the SWI-Prolog version, which is by defining a clause for the term_expansion/2 predicate. This mechanism works differently in different systems or is altogether missing.
term_expansion(pairwise_listwise(PairPred,ListPred), ExpandedTerm) :-
TerminalCall =.. [ListPred,_,[]],
RecursiveCall =.. [ListPred,Y,[X|Xs]],
SingleCall =.. [PairPred,Y,X],
FinalCall =.. [ListPred,Y,Xs],
ExpandedTerm = [TerminalCall, (RecursiveCall :- (SingleCall, FinalCall))].
In this clause, ExpandedTerm is a list defining the two clauses we want to define and all the terms in it are built from the predicate names using =... One can then define the new predicate as follows:
pairwise_listwise(whatever, all_whatever).
When this code is loaded, that clause will be expanded and replaced by two clauses defining the new predicate all_whatever. And now one can call for instance all_whatever(Y1,Xs1).
My preference goes to the first approach (conceptually simpler and works across Prolog versions) but I think it is also useful to be aware of the existence of the term expansion mechanism as well.

Simple Prolog program: "Arguments are not sufficiently instantiated" error

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.

Prolog: generate queries out of DCG

I currently have a small Prolog database containing a few people and some predicates for relations. For example:
female(anna).
female(susan).
male(john).
male(timmy).
siblings(anna, susan).
siblings(anna, john).
siblings(susan, john).
sibling(X, Y) :- siblings(X, Y) ; siblings(Y, X).
%X is brother of Y
brother(X, Y) :- male(X), sibling(X, Y).
and I have a DCG which can determine valid questions like
"who is the brother of john", which also works well.
question --> ip, verb, article, noun, pronoun, name.
Now I want my program to make a call to my family-database out of noun and name like this:
noun(X, name).
Which in the example then should be
brother(X, anna).
and then return the answer as a natural-language answer like:
"the brother of anna is john"
Defining the grammer for the answer sentence is no problem either. The only thing I don't know is, how to make the call from my DCG to my database and to get the right values filled into it. I looked around for quite some time now - perhaps I don't know the right search terms - and couldnt find something related to this.
I hope you guys have some good ideas ! :)
Thank you.
Invoking Prolog predicates from DCGs
Regular way: Use {}/1
Use the nonterminal {}//1 to call arbitrary Prolog goals from within DCGs.
For example:
verb --> [V], { verb(V) }.
This defines a nonterminal verb//1. This DCG describes a list consisting of the element V such that verb(V) holds, where verb/1 is a normal Prolog predicate.
In a sense even more regular: Use DCGs throughout!
Note that there is a second way to do this, which is in a sense even easier to understand: You can simply turn everything into DCG nonterminals!
For example, you could say:
female(anna) --> [].
female(susan) --> [].
male(john) --> [].
male(timmy) --> [].
You could then simply use these nonterminals directly. You could define a term_expansion/2 rule that does such a transformation automatically.
In your specific case, using {}/1 is likely preferable, because you already have existing Prolog facts and. But there are definitely cases where using DCGs throughout is preferable.
EDIT: From your comment, I see your question is a bit more involved.
The question is rather about:
Constructing Prolog goals from sentences
This is extremely straight-forward: Essentially, you only need to describe the relation between the Prolog goals you want and the corresponding sentences.
We do this by introducing a new argument to the DCG, and that argument will denote the Prolog goal that needs to be executed to answer the sentence. In your example, you want to relate the sentence "Who is the brother of susan?", to a call of the Prolog predicate brother(X, susan). You already have a nonterminal sentence//0 that describes such sentences. You only need to make explicit the goal that such sentences correspond to. For example:
sentence_goal(noun(X, name)) --> ip, v, a, noun, p, name.
This is only used to illustrate the principle; I'm not claiming that this is already the full solution. The point is simply to show that you can reason about Prolog goals in exactly the same way as about all other terms.
You can then invoke the actual goals in two phases:
first, relate the given sentence to the goal, using this new nonterminal sentence_goal//1
simply call the goal, using call/1 or invoking it directly.
For example:
?- phrase(sentence_goal(Goal), Sentence), Goal.
In your case, all that remains is relating such sentences to the Prolog goals you want to invoke, such as brother_of/2 etc.
None of this needs any side-effects (write/1)! Instead, concentrate on describing the relations between sentences and goals, and let the Prolog toplevel do the printing for you.

Prolog - Return result instead of printing in algorithm

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.

Resources