Firstly, I'm not a prolog programmer. I'm doing an assignment for school where we build a small expert system. I've chosen to use prolog for the assignment and I'm following this book: http://www.amzi.com/distribution/files/xsip_book.pdf. Specifically I'm looking at chapter 2.
There is a procedure in this book that I would like to use called "ask." It can be found on page 14. Ask, uses another procedure called "known" to remember the answers to questions. I have basically copied this procedure for use in my code, but I am getting an existence error related to the "known" procedure. Not being a prolog programmer, I don't know how to debug it. Hopefully someone can help.
Here is a sample run of my code:
| ?- species(X).
uncaught exception: error(existence_error(procedure,known/3),ask/2)
Here is the code:
species(limba) :- %There are a bunch of these
distribution(west_africa),
color(tan_with_black_streaks),
figure(plain),
janka_hardness(670),
workability(easy).
distribution(X) :- ask(distribution, X).
color(X) :- ask(color, X).
figure(X) :- ask(figure, X).
janka_hardness(X) :- ask(janka_hardness, X).
workability(X) :- ask(workability, X).
ask(A, V) :-
known(yes, A, V),
!.
ask(A, V) :-
known(_, A, V),
!,
fail.
ask(A, V) :-
write(A:V),
write('? : '),
read(Y),
asserta(known(Y, A, V)),
Y == yes.
This program expects known/3 to be dynamic (and the book you pointed to says this). That is, it's created and managed at run time. The Prolog documentation tells you how to declare a dynamic predicate. You might want to read through it. – lurker
Related
I'm new to prolog.
The idea of my project is to say "The room X is free if none is a guest of X, while X is taken if a family lives in X".
I use a predicate
guest(FamilySurname,RoomTaken)
So this mean that a family has taken that room.
taken(X) :- guest(_,X).
So if a family lives in room X, then X is taken.
My problem is how could i say that the room X is free? I should use a kind of NOT, like:
free(X) :- "NOT EXIST" guest(_,X).
How could i translate that "NOT EXIST" in prolog?
I have tried with ! but it doesn't work properly... maybe I'm placing it in the wrong way.
Sorry for my english.
Check the following code:
taken(X, Y) :- guest(Y,X).
free(X) :- \+ guest(_,X).
I made the a little change to taken, now it shows you who is on that room.
guest(albert, 123).
?- taken(123, R).
R = albert.
And the free() predicate it's pretty straightforward, I used the negation operator, you can check How to negate in Prolog
The code in the first answer does not seem to be a solution, i.e. the query ?- free(X) will not give an answer, where as the query ?- free(foo) will be successful. One needs to consider query floundering in Prolog into account, i.e. all variables
Consider the following code in which two alternatives for presenting the free predicate.
room(123).
room(124).
guest(albert, 123).
taken(Room) :- guest(_, Room).
free2(Room) :- room(Room),
\+ taken(Room).
free(Room) :- room(Room),
forall(guest(_, RoomTaken),
RoomTaken \= Room).
Why this program answers False in SWI-PROLOG?
sor(x, y):- sorted(y), perm(x, y).
sorted([]).
sorted([x, []]).
sorted([x, y, z]):- mi(x, y), sorted([y, z]).
perm([], []).
perm([x,y],[u,v]):- delete(u,[x,u],z), perm(z,v).
delete(x,[x,y],y].
delete(x, [y, z], [y, w]):- delete(x,z,w).
mi(0, x).
mi(s(x), s(y)):- mi(x, y).
for the query ?-
sor([s(s(s(s(s(0))))), s(s(s(s(s(s(0)))))), s(s(s(0))), s(s(0)), []], y).
This is an adaptation to SWIProlog of an inefficient sorting-program used as example in the book Foundations of Logic Programming, by Loyd (you can find the original SLOWSORT program example in this pdf, on page 9)
SWI Prolog is a standard Prolog, isn't it?
Edit
Now I have tried to correct the program (looking a little to the lists syntax in Prolog)
sor(X, Y):- perm(X, Y), sorted(Y).
sorted([]).
sorted([X|[]]).
sorted([X|[Y|Z]]):- mi(X, Y), sorted([Y|Z]).
perm([], []).
perm([X|Y],[U|V]):- delete(U,[X|Y],Z), perm(Z, V).
delete(X,[X|Y],Y).
delete(X, [Y|Z], [Y|W]):- delete(X, Z, W).
mi(0, X).
mi(s(X), s(Y)):- mi(X, Y).
and changing the query in
sor([s(s(s(s(s(0)))))|[ s(s(s(s(s(s(0))))))|[s(s(s(0)))|[ s(s(0))|[]]]]], Y).
Well, Prolog now gives success, but it gives this substitution
Y = [s(s(0)), s(s(s(0))), s(s(s(s(s(0))))), s(s(s(s(s(s(...))))))]
and I don't understand the meaning of (...): Why not (0)?
Edit2
I notice that after giving the command swipl -s slowsort.pl I obtain this error message
Warning: /home/navigazione/Scrivania/slowsort.pl:3:
Singleton variables: [X]
Warning: /home/navigazione/Scrivania/slowsort.pl:9:
Singleton variables: [X]
It seems to refer to 3th and 9th rows of the program, but I don't understand what it means.
Great, you managed to translate it to correct Prolog :)
What you see is the top level trying to make things readable by omitting stuff (the ... means there is stuff there that is not shown). See this question and answers for different ways you can tell the top level to show the complete term instead of hiding parts of it.
As for the singleton variable warnings, it just tells you that you have logical variables (on lines 3 and 9) that you have only mentioned once in their syntactical scope. You can write _X instead of X to make it explicit that you are not using the value of the variable in that scope.
I'm trying to compare two people and from those 2 people if the person had played someone before and won then lost to the newer person then that person technically is above from everyone else.
For example, It's set up like this:
Example of how it's set up: winner(won, lost).
winner(john, jacob).
winner(mike, john).
winner(scott, mike).
winner(matt, scott).
winner(X, Z) :- winner(X, Y), winner(Y, Z).
If I call: winner(matt, mike). It'll return true since matt beat scott which means he also beats mike since mike lost to scott.
Essentially I want to be able to call winner(matt, jacob). and it'll return true.
I have it only querying on tier down with that current rule, how would I go about querying through unlimited tiers? I'm confused on how to approach this.
You need two predicates. One for the basic facts, winner/2, and another for the transitive relation. For example:
transitive_winner(X, Y) :-
winner(X, Y).
transitive_winner(X, Z) :-
winner(X, Y),
transitive_winner(Y, Z).
With this definition and your winner/2 facts, you can ask e.g.
?- transitive_winner(mike, Y).
Y = john ;
Y = jacob ;
false.
You need to be careful when defining this transitive relations, however, to avoid left-recursion as in:
transitive_winner(X, Z) :-
transitive_winner(Y, Z),
winner(X, Y).
In Prolog systems that don't support tabling, a call to transitive_winner/2 would result in a stack overflow error.
I would like to build my own coroutines in Prolog.
I'd like to add some extra functionalities.
Writing a vanilla interpreter for coroutines should be on the teaching list of every Prolog course. It is quite simple, here you see the normal vanilla interpreter, simplified:
% solve(+Term)
solve(true).
solve((A,B)) :- solve(A), solve(B).
solve(H) :- clause(H, B), solve(B).
Now for corouting, in the sense of suspending goals via freeze/2, just add an additional input output parameter pair with the delayed goals, for a specification of select/3 see (*):
% solve(+Term, +List, -List)
solve(G, L, R) :- select(freeze(V, F), L, H),
nonvar(V), !,
solve((F,G), H, R).
solve(freeze(V, G), L, [freeze(V,G)|L]) :- var(V), !.
solve(freeze(_, G), L, R) :- solve(G, L, R).
solve(true, L, L).
solve((A,B), L, R) :- solve(A, L, H), solve(B, H, R).
solve(H, L, R) :- clause(H, B), solve(B, L, R).
You can use the above vanilla interpreter to study different wake-up strategies. I am not sure whether it captures existing Prolog systems. But you could run examples such as:
?- freeze(X, member(X, [the(1), the(2)])), X = the(Y).
successfully, by posing the following question:
?- solve((freeze(X, member(X, [the(1), the(2)])), X = the(Y), true), [], L).
The ", true" is needed to check a last time for woken up goals. If L is returned empty then all frozen goals where woken up. Otherwise there are some pending frozen goals. Which is sometimes called floundering.
The above prototype also leads to a natural implementation of coroutines via thin attributes, the undo/1 and some little support of the interpreter by a goal injection queue. I will post about this soon somewhere else.
Bye
(*)
https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue
One possible solution would be to use the term-expansion mechanism provided by some Prolog systems and Logtalk to rewrite calls to e.g. the freeze/2 predicate to do the extra steps you want. One must be careful, however, to not expand a call to a predicate into another goal that calls the same predicate as goal-expansion is recursively applied until a fixed-point is reached. The Logtalk implementation of the term-expansion mechanism makes it easy to avoid this trap (with the additional advantage of portability as you can use Logtalk with most Prolog systems) by using a compiler bypass control construct, {}/1. A silly example would be:
:- object(my_expansions,
implements(expanding)).
goal_expansion(
freeze(Var,Goal),
( write('If you instantiate me, I will run away!\n'),
{freeze(Var,Goal)}, % goal will not be further expanded
write('Bye!\n')
)
).
:- end_object.
This object can then be used as an hook object for the compilation of source files containing calls to freeze/2 that you want to expand. Something like (assuming that the object above is saved in a file with the name my_expansions.lgt and that the source file that you want to expand is named source.lgt):
?- logtalk_load(my_expansions), logtalk_load(source, [hook(my_expansions)]).
For full details see the Logtalk documentation and examples.
There might be a clean way that I'm not aware of doing the same using the a Prolog system own term-expansion mechanism implementation. Anyone?
likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).
likes(john,X):-likes(X,john), X\=john.
Hi there, above is a very simple prolog file, with some facts and only one rule: John likes anyone who likes him.
But after loading this file and ask Prolog the following query:
likes(john,X).
The program crashes. The reason is somehow prolog gets stuck at likes(john,john) even though the rule states that X\=john.
Any advice?
Ironically, given the site we're on, you're getting a stack overflow.
It does this because of the order of execution that prolog uses, it's going to go into an infinite recursion at likes(X,john) in your rule, it activates the rule again - not a fact - never getting to the X\=john bit.
One way to fix this is to have your rule named differently from your fact like this:
kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).
likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.
Note the reversal of X and Y in the kindoflikes in the two rule definitions.
So you get:
?- likes(john,X).
X = mary ;
X = tom ;
X = book.
But you're not locked into finding what john likes, and you can do:
?- likes(jerry,X).
X = tom ;
X = cheese.
Your first question was why your program crashes. I am not sure what kind of Prolog system you are using, but many systems produce a clean "resource error" which can be handled from within Prolog.
Your actual problem is that your program does not terminate for the query likes(john, X). It gives you the expected answers and only then it loops.
?- likes(john,X).
X = book
; X = mary
; X = tom
; resource_error(local_stack). % ERROR: Out of local stack
You have been pretty lucky that you detected that problem so rapidly. Imagine more answers, and it would have not been that evident that you have the patience to go through all answers. But there is a shortcut for that. Ask instead:
?- likes(john, X), false.
This false goal is never true. So it readily prevents any answer. At best, a query with false at the end terminates. Currently this is not the case. The reason for this non-termination is best seen when considering the following failure-slice (look up other answers for more details):
?- likes(john,X), false.
loops.
likes(tom,jerry) :- false.
likes(mary,john) :- false.
likes(mary,mary) :- false.
likes(tom,mouse) :- false.
likes(jerry,jerry) :- false.
likes(jerry,cheese) :- false.
likes(mary,fruit) :- false.
likes(john,book) :- false.
likes(mary,book) :- false.
likes(tom,john) :- false.
likes(john,X) :-
likes(X,john), false,
X\=john.
So it is this tiny little part of your program that is responsible for the stack overflow. To fix the problem we have to do something in that tiny little part. Here is one: add a goal dif(X, john) such that the rule now reads:
likes(john,X) :-
dif(X, john),
likes(X,john).
dif/2 is available in many Prolog systems like: SICStus, SWI, YAP, B, IF.