I'm trying to test out recursion in prolog. Based on the KB and conditional statements below, I tried to make a recursive call and wanted to use the one specifically for "eastOf(X,Y) :- westOf(X,Z),eastOf(Z,Y)" The query I am using is "eastOf(ave,yonge)" which should use that recursive call and state that X is ave, Y is yonge and Z is collegePark. However the proglog program i am using current (ECliPSe) iss giving me this error "*** Overflow of the local/control stack!
You can use the "-l kBytes" (LOCALSIZE) option to have a larger stack.
Peak sizes were: local stack 11024 kbytes, control stack 120048 kbytes"
Find below my .pl file
eastOf(collegePark,yonge).
eastOf(sushi,eaton).
eastOf(X,Y) :- westOf(Y,X).
eastOf(X,Y) :- westOf(X,Z), eastOf(Z,Y).
westOf(ellington,yonge).
westOf(ryerson,sushi).
westOf(ave,collegePark).
westOf(X,Y) :- eastOf(Y,X).
westOf(X,Y) :- eastOf(X,Z), westOf(Z,Y).
eastOf(X,Y) :- westOf(Y,X).
westOf(X,Y) :- eastOf(Y,X).
The infinite loop has occurred in the combination of these two predicates.
Even if stack size is large, size over occurs.
I change your program as follows.
eastOf_data(collegePark,yonge).
eastOf_data(sushi,eaton).
eastOf(X,Y) :- westOf_data(Y,X).
eastOf(X,Y) :- westOf_data(X,Z), eastOf_data(Z,Y).
westOf_data(ellington,yonge).
westOf_data(ryerson,sushi).
westOf_data(ave,collegePark).
westOf(X,Y) :- eastOf_data(Y,X).
westOf(X,Y) :- eastOf_data(X,Z), westOf_data(Z,Y).
I think you meant to use eastOf(yonge,collegePark) as your first statement. Right now it never finds an atomic statement starting with either 'ave' or 'yonge', and keeps looping between eastOf(X,Y) :- westOf(Y,X) and westOf(X,Y) :- eastOf(Y,X).
Related
Given the following database:
location(desk, office).
location(apple, kitchen).
location(flashlight, desk).
location('washing machine', cellar).
location(nani, 'washing machine').
location(broccoli, kitchen).
location(crackers, kitchen).
location(computer, office).
location(envelope, desk).
location(stamp, envelope).
location(key, envelope).
is_contained_in(X, Y) :-
location(Z, Y),
is_contained_in(X, Z).
I expect the following query
is_contained_in(Y, kitchen).
to yield all the items are inside the kitchen. Instead, all the output I get is false. Furthermore, I expect my query to yield me a list of all the items that exist inside the kitchen regardless of whether or not they are inside other items.
Why is the the is_contained_in predicate not giving me the desired result with the query
is_contained_in(Y, kitchen).
The problem is that is_contained_in(X, Y) does not have a condition to match when X is directly located in Y, and because any containment relation will eventually require direct location to match, it won't find anything. You need an extra clause to handle that case:
is_contained_in(X, Y) :- location(X, Y).
What I have...
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
What I'm querying...
mirror(b(nil,a,b(nil,b,nil)), Result).
Expected result
Result = b(b(nil,b,nil),a,nil).
The tree b(Left,Right,Head) is the first argument of mirror, NewTree is the goal. mirror(Left,NewLeft) recurses through the left side and yields the goal NewLeft, same for Right. NewTree is the tree b(NewRight,Head,NewLeft).
I'm not sure why this isn't working could someone please help.
Based on your current code
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
you are very close.
As noted in a comment by Steven
You're missing the base case for mirror/2. What should NewTree be when the input tree is nil?
is very helpful.
Before getting to the full working predicate lets clear up a other things.
The predicate for tree is not needed.
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
I don't know if you are showing this to shows us that you know how a tree works or what but for others reading this predicate it is not needed for the answer.
That leaves only
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
A standard style with using a variable that works like an input and output with several usages is for the starting one, append a 0, then for each succeeding use increase the appended number and for the result append nothing.
mirror(b(Left0,Head,Right0), NewTree) :-
mirror(Left0,Left),
mirror(Right0,Right),
NewTree = b(Right,Head,Left).
Next =/2 is just doing unification. This can be refactored as such
mirror(b(Left0,Head,Right0), b(Right,Head,Left)) :-
mirror(Left0,Left),
mirror(Right0,Right).
Now back to your problem
Since a tree is a recursive structure, it can be processed with with recursion. Predicates that work on recursive data structures need a base clause and a clause to do the recursion. You already have a clause to do the recursion but just need a base clause.
If you use the SWI-Prolog gui tracer on your code for the query
mirror(b(nil,a,b(nil,b,nil)), Result).
you will see
that when one of the branches is just nil there is no mirror/2 rule to handle this case.
Adding
mirror(nil,nil).
will solve your problem.
?- mirror(b(nil,a,b(nil,b,nil)), Result).
Result = b(b(nil, b, nil), a, nil).
The entire predicate.
mirror(nil,nil).
mirror(b(Left0,Head,Right0), b(Right,Head,Left)) :-
mirror(Left0,Left),
mirror(Right0,Right).
I am still trying to understand the Prolog logic and have stumbled upon a problem.
I am trying to save values found within recursive calls, to pass on or gather.
As such:
main([]) :- !.
main([H|Tail]) :- findall(X,something(_,_,X),R),
getValueReturn(R,H,Lin, Lout),
main(Tail).
% X is the Head from main
getValueReturn([H|Tail],X,Lin, Lout) :- subset(X, H) ->
findall(A,something(A,_,H),L1),
append(Lin,L1,Lout),
getValueReturn(Tail,X,Lout,L)
;
getValueReturn(Tail,X,Lin,Lout).
I would like to gather the results from findall in getValueReturn, combine them, and send them back to main, which can then use them.
How do I create and add to a list within getValueReturn?
Similarly, how can I save the list in my main for all recursive calls?
EDIT:
I edited the code above as per a comment reply, however when I run this through trace, the list deletes all elements when the empty list is found.
What am I doing wrong? This is the first time I try to use the concept of building a list through recursion.
You should post complete code that can be run, with example data. I have not tested this.
You need to pass L around on the top-level also. Using the same variable names for different parameters in adjacent procedures does not improve readability.
main([E|Es],L0,L) :-
findall(X,something(_,_,X),Rs),
getValueReturn(Rs,E,L0,L1),
main(Es,L1,L).
main([],L,L).
getValueReturn([R|Rs],E,L0,L) :-
( subset(E,R) ->
findall(A,something(A,_,R),New),
append(L0,New,L1),
getValueReturn(Rs,E,L1,L)
; getValueReturn(Rs,E,L0,L) ).
getValueReturn([],_,L,L).
A variable can only have one value in Prolog. In your code, for example, Lout is the output from append/3, an input to a recursive call of getValueReturn/4, and then also the output on the top-level. This is probably not going to do what you want.
I have found the best way to do what I was trying to was to use asserta/z when a result was found, and then gather these results later on.
Otherwise the code became overly complicated and did not function as intended.
Why does Probe not execute? This is not the whole program, but should be sufficient code to find an answer. Yes, I already scoured Stack Overflow for an answer but there is not much help for Prolog. It is part of a minesweeper game.
play :-
play(0).
play(M) :-
N is M + 1,
Suf <- N,
display_board(visible), nl,
format("Your ~d~a move~n", [N,Suf]),
retrieve('Coordinates? ', [A,B]),
format("DEBUG: probing at coordinates [~d,~d]~n", [A, B]),
!, probe(A,B),
play(N).
probe(X, Y) :-
write("enter probe"),
located_at(Who, X, Y, C),
C = 'b',
write('should probe '),
write('at ['),
write(X), write(','), write(Y), write(']'), nl.
:- style_check(+singleton).
Let us step back and first try to find out: Why does the program not even compile?
When consulting the program you posted, I get:
ERROR: file.pl:6:6: Syntax error: Operator expected
This is the line that says:
Suf <- N
That's not valid Prolog syntax.
Therefore, I suggest to fix this first.
In fact, I further get:
Warning: file.pl:14: Singleton variables: [Who]
That's also not a good sign. But the ERROR is more severe, preventing compilation of the whole clause.
I wanted to write evaluating predicate in Prolog for arithmetics and I found this:
eval(A+B,CV):-eval(A,AV),eval(B,BV),CV is AV+BV.
eval(A-B,CV):-eval(A,AV),eval(B,BV),CV is AV-BV.
eval(A*B,CV):-eval(A,AV),eval(B,BV),CV is AV*BV.
eval(Num,Num):-number(Num).
Which is great but not very DRY.
I've also found this:
:- op(100,fy,neg), op(200,yfx,and), op(300,yfx,or).
positive(Formula) :-
atom(Formula).
positive(Formula) :-
Formula =.. [_,Left,Right],
positive(Left),
positive(Right).
?- positive((p or q) and (q or r)).
Yes
?- positive(p and (neg q or r)).
No
Operator is here matched with _ and arguments are matched with Left and Right.
So I came up with this:
eval(Formula, Value) :-
Formula =.. [Op, L, R], Value is Op(L,R).
It would be DRY as hell if only it worked but it gives Syntax error: Operator expected instead.
Is there a way in Prolog to apply operator to arguments in such a case?
Your almost DRY solution does not work for several reasons:
Formula =.. [Op, L, R] refers to binary operators only. You certainly want to refer to numbers too.
The arguments L and R are not considered at all.
Op(L,R) is not valid Prolog syntax.
on the plus side, your attempt produces a clean instantiation error for a variable, whereas positive/1 would fail and eval/2 loops which is at least better than failing.
Since your operators are practically identical to those used by (is)/2 you might want to check first and only then reuse (is)/2.
eval2(E, R) :-
isexpr(E),
R is E.
isexpr(BinOp) :-
BinOp =.. [F,L,R],
admissibleop(F),
isexpr(L),
isexpr(R).
isexpr(N) :-
number(N).
admissibleop(*).
admissibleop(+).
% admissibleop(/).
admissibleop(-).
Note that number/1 fails for a variable - which leads to many erroneous programs. A safe alternative would be
t_number(N) :-
functor(N,_,0),
number(N).