What's the most idiomatic approach to output prolog code from a prolog program (as a side effect)?
For instance, in a simple case, I might want to write a Program that, given a text input, yields another Prolog program representing the text as a directed graph.
I understand this question is somewhat vague, but I've resigned to consulting Stackoverflow after failing to find a satisfying answer in the available Prolog Meta-Programming literature, which mostly covers applications of meta-circular interpreters.
If you feel this question might be better articulated some other way, please edit it or leave a comment.
The most idiomatic way is always to stay pure and avoid side effects.
Let the toplevel do the writing for you!
To generate a Prolog program, you define a relation that says for example:
program(P) :- ...
and then states, in terms of logical relations, what holds about P.
For example:
program(P) :-
P = ( Head :- Body ),
Head = head(A, B),
Body = body(A, B).
Example query and answer:
?- program(P).
P = (head(_G261, _G262):-body(_G261, _G262)).
So, there's your program, produced in a pure way.
If you want to write it, use portray_clause/1:
?- program(P), portray_clause(P).
head(A, B) :-
body(A, B).
...
This can be useful in a failure driven loop, to produce many programs automatically.
writeq/1 (or format('~q', [...])) produces output that can be read back. Usually you need also to put a full stop after a clause body. For instance, try
?- A_Clause = (X is 1+Y, write('X is '), write(X), nl), format('~q.~n', [A_Clause]).
Readability of code suffers from loosing variables 'nice names', but the functionality is there...
edit
as noted by #false, a space before the dot will avoid a bug in case the output term would finish with a dot
Related
So I am currently learning prolog and I can't get my head around how this language works.
"It tries all the possible solutions until it finds one, if it doesn't it returns false" is what I've read that this language does. You just Describe the solution and it finds it for you
With that in mind, I am trying to solve the 8 queens problem ( how to place 8 queens on a chess board without anyone threatening the others).
I have this predicate, 'safe' that gets a list of pairs, the positions of all the queens and succeeds when they are not threatening each other.
When I enter in the terminal
?- safe([(1,2),(3,5)]).
true ?
| ?- safe([(1,3),(1,7)]).
no
| ?- safe([(2,2),(3,3)]).
no
| ?- safe([(2,2),(3,4),(8,7)]).
true ?
it recognizes the correct from the wrong answers, so it knows if something is a possible solution
BUT
when I enter
| ?- safe(L).
L = [] ? ;
L = [_] ? ;
it gives me the default answers, even though it recognizes a solution for 2 queens when I enter them.
here is my code
threatens((_,Row),(_,Row)).
threatens((Column,_),(Column,_)).
threatens((Column1,Row1),(Column2,Row2)) :-
Diff1 is Column1 - Row1,
Diff2 is Column2 - Row2,
abs(Diff1) =:= abs(Diff2).
safe([]).
safe([_]).
safe([A,B|T]) :-
\+ threatens(A,B),
safe([A|T]),
safe(T).
One solution I found to the problem is to create predicates 'position' and modify the 'safe' one
possition((0,0)).
possition((1,0)).
...
...
possition((6,7)).
possition((7,7)).
safe([A,B|T]) :-
possition(A),
possition(B),
\+ threatens(A,B),
safe([A|T]),
safe(T).
safe(L,X):-
length(L,X),
safe(L).
but this is just stupid, as you have to type everything explicitly and really really slow,
even for 6 queens.
My real problem here, is not with the code itself but with prolog, I am trying to think in prolog, But all I read is
Describe how the solution would look like and let it work out what is would be
Well that's what I have been doing but it does not seem to work,
Could somebody point me to some resources that don't teach you the semantics but how to think in prolog
Thank you
but this is just stupid, as you have to type everything explicitly and really really slow, even for 6 queens.
Regarding listing the positions, the two coordinates are independent, so you could write something like:
position((X, Y)) :-
coordinate(X),
coordinate(Y).
coordinate(1).
coordinate(2).
...
coordinate(8).
This is already much less typing. It's even simpler if your Prolog has a between/3 predicate:
coordinate(X) :-
between(1, 8, X).
Regarding the predicate being very slow, this is because you are asking it to do too much duplicate work:
safe([A,B|T]) :-
...
safe([A|T]),
safe(T).
Once you know that [A|T] is safe, T must be safe as well. You can remove the last goal and will get an exponential speedup.
Describe how the solution would look like and let it work out what is
would be
demands that the AI be very strong in general. We are not there yet.
You are on the right track though. Prolog essentially works by enumerating possible solutions and testing them, rejecting those that don't fit the conditions encoded in the program. The skill resides in performing a "good enumeration" (traversing the domain in certain ways, exploiting domain symmetries and overlaps etc) and subsequent "fast rejection" (quickly throwing away whole sectors of the search space as not promising). The basic pattern:
findstuff(X) :- generate(X),test(X).
And evidently the program must first generate X before it can test X, which may not be always evident to beginners.
Logic-wise,
findstuff(X) :- x_fulfills_test_conditions(X),x_fullfills_domain_conditions(X).
which is really another way of writing
findstuff(X) :- test(X),generate(X).
would be the same, but for Prolog, as a concrete implementation, there would be nothing to work with.
That X in the program always stands for a particular value (which may be uninstantiated at a given moment, but becomes more and more instantiated going "to the right"). Unlike in logic, where the X really stands for an unknown object onto which we pile constraints until -ideally- we can resolve X to a set of concrete values by applying a lot of thinking to reformulate constraints.
Which brings us the the approach of "Constraint Logic Programming (over finite domains)", aka CLP(FD) which is far more elegant and nearer what's going on when thinking mathematically or actually doing theorem proving, see here:
https://en.wikipedia.org/wiki/Constraint_logic_programming
and the ECLiPSe logic programming system
http://eclipseclp.org/
and
https://www.metalevel.at/prolog/clpz
https://github.com/triska/clpfd/blob/master/n_queens.pl
N-Queens in Prolog on YouTube. as a must-watch
This is still technically Prolog (in fact, implemented on top of Prolog) but allows you to work on a more abstract level than raw generate-and-test.
Prolog is radically different in its approach to computing.
Arithmetic often is not required at all. But the complexity inherent in a solution to a problem show up in some place, where we control how relevant information are related.
place_queen(I,[I|_],[I|_],[I|_]).
place_queen(I,[_|Cs],[_|Us],[_|Ds]):-place_queen(I,Cs,Us,Ds).
place_queens([],_,_,_).
place_queens([I|Is],Cs,Us,[_|Ds]):-
place_queens(Is,Cs,[_|Us],Ds),
place_queen(I,Cs,Us,Ds).
gen_places([],[]).
gen_places([_|Qs],[_|Ps]):-gen_places(Qs,Ps).
qs(Qs,Ps):-gen_places(Qs,Ps),place_queens(Qs,Ps,_,_).
goal(Ps):-qs([0,1,2,3,4,5,6,7,8,9,10,11],Ps).
No arithmetic at all, columns/rows are encoded in a clever choice of symbols (the numbers indeed are just that, identifiers), diagonals in two additional arguments.
The whole program just requires a (very) small subset of Prolog, namely a pure 2-clauses interpreter.
If you take the time to understand what place_queens/4 does (operationally, maybe, if you have above average attention capabilities), you'll gain a deeper understanding of what (pure) Prolog actually computes.
Hi :) Beginner to Prolog.
I have this code:
dog(rex).
owns(bill,rex).
animallover(X):-owns(X,Y),dog(Y).
not(beat(X,Y)):-animallover(X),isAnimal(Y).
beat(bill,tom);beat(bull,tom).
iscat(tom).
isAnimal(X):-iscat(X).
This yields the error: No permission to modify static procedure `(;)/2'
What's wrong there?
Thanks for your help.
dog(rex).
owns(bill,rex).
animallover(X):-owns(X,Y),dog(Y).
notbeat(X,Y):-animallover(X),isAnimal(Y).
not(notbeat(bill,tom),notbeat(bull,tom)).
iscat(tom).
isAnimal(X):-iscat(X).
This solves the problem. But we want to answer the question "Who hit Tom?"
That way we can only ask
?- nothit(X,tom).
and this would yield bill.
So how can we change the code so we can ask who did hit Tom?
The source of your problem is some code that would, in a lesser language, produce a syntax error, but which is syntactically valid but definitely meaningless Prolog.
This part of your code is totally fine:
dog(rex).
owns(bill, rex).
animallover(X) :- owns(X, Y), dog(Y).
Whitespace is free. :)
This is your first problem:
not(beat(X,Y)) :- animallover(X), isAnimal(Y).
I'm not sure what you're trying to say here because I've been doing Prolog too long. But what you are saying here, stated a little differently, is this:
not(Q) :- Q = beat(X, Y), ...
In other words, the procedure you are defining here is not/1, rather than anything to do with beat/2. You've got too much stuff in the head. This is kind of an unusual problem for a beginner; usually people with exposure to other languages would make the error of doing too much assignment on the right side of :- rather than the left side.
In any case, another way to read Q :- P is, "to prove Q, I must first prove P." That's how Prolog thinks about it. Or, "if P, then I can conclude Q." So, you're teaching Prolog how to make a conclusion called not, which is almost certainly not what you mean.
Now, on to your next line, where the error occurs:
beat(bill, tom); beat(bull, tom).
Prolog deals in what are called Horn clauses. The generic Horn clause looks like Q :- P, but if you omit :- P, what you get is usually called a fact. In this case, the entire thing you have on that line is one fact. The head of that expression turns out to be ;, so what you've actually written is this:
A ; B :- A = beat(bill, tom), B = beat(bull, tom).
You're trying to redefine ;/2 here, in essence, and Prolog is not allowing that because ; is too important. What you probably meant here was just a period separating two facts: beat(bill, tom). beat(bull, tom)..
I hope this helps get you over the hump.
In the line
beat(bill,tom);beat(bull,tom).
you seem to mean "Bill beat Tom or Bull beat Tom".
But by Prolog's rules you are instead trying to redefine ;, which isn't allowed, and you can't write "Bill beat Tom or Bull beat Tom" as a fact.
This is an easy question: I've seen this example in a Prolog text book.
It is implementing if-then-else using a cut.
if_then_else(P, Q, R) :- P, !, Q.
if_then_else(P, Q, R) :- R.
Can anyone explain what this program is doing, and why it is useful?
The most important thing to note about this program that it is definitely not a nice relation.
For example, from a pure logic program, we expect to be able to derive whether the condition had held if we pass it the outcome. This is of course in contrast to procedural programming, where you first check a condition and everything else depends on the condition.
Also other properties are violated. For example, what happens if the condition actually backtracks? Suppose I want to see conclusions for each solution of the condition, not just the first one. Your code cuts away these additional solutions.
I would also like to use the relation in other cases, for example, suppose I want to detect superfluous if-then-else constructs in my code. These are solutions to queries similar to:
?- if_then_else(NoMatter, Same, Same).
If if_then_else/3 were a pure relation, we could use it to answer such queries. As it is currently implemented, it yields incorrect results for such queries.
See logical-purity and if_/3 for more information.
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.
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
Mr Boddy was having an affair with Ms. Green.
Professor Plum is married to Ms. Green.
Mr. Boddy was very rich.
Colonel Mustard is very greedy.
Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect.
Clearly indicate this line in your source comments so that it can be removed/added for
grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false into your program. I will add as many false goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.
married(profPlum, msGreen) :- false.
married(X,Y) :- married(X,Y), false, married(Y,X).
hate(X,Y) :- married(X,Spouse), false, affair(Y,Spouse).
suspect(X,Y):- hate(X,Y), false.
suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :- as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided X is married to Y and Y is married to X
we can conclude that
X is married to Y.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen) holds but married(msGreen, profPlum) does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2 and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1 or (\+)/1 must not appear in the fragment.
2 This example is of interest to #larsmans.
The problem is the recursive rules of the predicates affair/2 and married/2. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2 predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.