Prolog, working with recursion [duplicate] - recursion

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).

Related

Mirror binary tree in Prolog

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).

Prolog, issues with base case failing

I'm currently writing a prolog A* search function, and ran into an issue with one of my queries. So I decided to manually test the base case, as that's where the trace was failing.
addAChild([Child],[],[Child]):-
write(woo empty).
I manually ran:
addAChild([c(1,1,p(1,2)),[]],[],A).
but it just fails.
Any help would be appreciated.
[Child] (a 1-element list) cannot unify with [c(1,1,p(1,2)),[]] (a 2-elements list).
That's why it is failing.
You can manually test in the interactive interpreter that those two terms fail to unify:
?- addAChild([Child],[],[Child]) = addAChild([c(1,1,p(1,2)),[]],[],A).
false.
and then you can inspect recursively which part is failing.
The term name (addAChild) and the arity (3) is the same, so we can rule off this issue.
Then proceed to unify each argument:
?- [Child] = A.
A = [Child].
?- [] = [].
true.
?- [Child] = [c(1,1,p(1,2)),[]].
false.

Why doesnt' probe execute?

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.

Recursive Decision Tree In Problems

So I am trying to draw the decision of tree of 2 Prolog problems, one that uses the accumulator and other that doesn't. Here are my problems and the solutions I did, respectively:
length([H|T],N) :- length(T,N1), N is N1+1.
length([ ],0).
Goal: ?: length([1,2,3],N)
Second one with accumulator:
length_acc(L,N) :- len_acc(L,0,N).
len_acc([H|T], A, N) :- A1 is A+1, len_acc(T, A1, N).
len_acc([], A, A).
Goal: ?-length_acc([1,2], N).
Are the decision trees correctly drawn? Or have I made a mistake? Whats the correct way to draw these kind of recursive decision tree?
Thanks.
The tree you are referring to is usually called a search-tree aka SLD-tree, not to be confused with a proof-tree.
Both the problems you have outlined are the most simple cases of search-trees:
there is only one solution
the query does not fail
each step in the search can only match a single clause (empty list vs non-empty list)
These three characteristics imply that there will only be a single branch in the SLD tree.
You'll get the following search-trees:
Note that for it to be a correct search-tree, at most one goal is resolved in each step, which makes search-trees very large... therefore it's common that people make simplified trees where multiple goals can be resolved in each step, which arguably are not true search-trees but illustrates the search in a more succint way.
Edges in the tree are labeled with substitutions that are applied to the variables as part of the unification algorithm.
Search-trees correspond closely to traces, and you can usually do a straight translation from a trace of your program to a search tree.
I advise you to study search-trees for queries that have multiple answers and branches that can fail, which gives more interesting trees with multiple branches. An example from The Art of Prolog by Sterling, Shapiro:
Program:
father(abraham, isaac). male(isaac)
father(haran, lot). male(lot).
father(haran, milcah). female(milcah).
father(haran, yiscah). female(yiscah).
son(X,Y):- father(Y,X), male(X).
daughter(X,Y):- father(Y,X), female(X).
Query:
?: son(S, haran)
Search-tree:
A nice way to understand something is to re-implement it yourself.
It's especially nice to implement Prolog when you already have Prolog to implement it with. :)
program( patriarchs, P ) :-
P = [ % [son(S, haran)] , % Resolvent
[father(abraham, isaac)] % Clauses...
, [father(haran, lot)] % [Head, Body...]
, [father(haran, milcah)]
, [father(haran, yiscah)]
, [male(isaac)]
, [male(lot)]
, [female(milcah)]
, [female(yiscah)]
, [son(X,Y), father(Y,X), male(X)]
, [daughter(X,Y), father(Y,X), female(X)]
].
solve( Program ):-
Program = [[] | _]. % empty resolvent -- success
solve( [[Goal | Res] | Clauses] ) :-
member( Rule, Clauses),
copy_term( Rule, [Head | Body]), % rename vars
Goal = Head, % unify head
append( Body, Res, Res2 ), % replace goal
solve( [Res2 | Clauses] ).
query( What, Query ):- % Query is a list of Goals to Solve
program( What, Program),
solve( [ Query | Program ] ).
Testing,
23 ?- query( patriarchs, [son(S, haran)] ).
S = lot ;
false.
Now the above solve/1 can be augmented to record the record of successful instantiations of Goal making the unifications Goal = Head possible.

issues regarding prolog backtracking to find other solution

I am beginner of Prolog.
what I have is a function traverse a list and return true when it satisfies the condition.
for example, check_version checks if the package version met the condition(eg. the version satisfies the condition such as greater than or less than the specific version) and check_all checks takes a list of versions and conditions to check one by one.
package('python', '2.6.5').
package('python', '2.5.4').
package('python', '1.5.2').
package('python', '3.1.0').
check_version(Pac, Ver, Cmp, V):-
package(Pac, V),
cmp_version(V, Ver, Cmp).
check_all( Pac, [], [], V):-
package(Pac, V).
check_all(Pac, [Ver], [Cmp], V):-
check_version(Pac, Ver, Cmp, V).
check_all(Pac, [Ver|VerS], [Cmp|CmpS], V):-
check_version(Pac, Ver, Cmp, V),
check_all(Pac, VerS, CmpS, V).
The problem I have is when try to find other solutions, it gives me duplicate solution.
I get:
check_all('python', ['3.0','2.4'], [lt,ge], V).
V = '2.6.5' ;
V = '2.6.5' ;
V = '2.5.4' ;
V = '2.5.4' .
expected:
check_all('python', ['3.0','2.4'], [lt,ge], V).
V = '2.6.5' ;
V = '2.5.4' .
I used trace to track it, and the problem I found, when it try to find another solution it back tracks and will return fail until find the right solution. Like the example above, apparently, it will return true for V='2.6.5' at first and take that to back track and run the functions, and we expect it returns false and then when it reach the beginning it run package('python', V) and V will take another value.
...
Exit: (7) check_all(python, ['3.0', '2.4'], [lt, ge], '2.6.5') ? creep
V = '2.6.5'
...
Fail: (9) check_version(python, '2.4', ge, '2.6.5') ? creep
Redo: (8) check_all(python, ['2.4'], [ge], '2.6.5') ? creep
Call: (9) check_version(python, '2.4', ge, '2.6.5') ? creep
Call: (10) package(python, '2.6.5') ? creep
Exit: (10) package(python, '2.6.5') ? creep
when back tracking, in check_all, it fails at check_all as we expected, but it returns true when it backtracks check_version and run package(python, '2.6.5') as V=2.6.5 a new value. so it return true again when V=2.6.5. is there any way to solve this problem?
To localize your problem, first reduce the size of your input. A single element suffices:
?- check_all('python', ['3.0'], [lt], V).
Now, which rules apply for a single element?
Both rules apply! So remove the more specialized one.
There is also another way how to localize such a problem. Simply compare the rules to each other and try to figure out a case where they both apply. The last rule applies for VerS = [] when also the first applies.
Applying a predicate to each element of a list is best done by a predicate that has the list as its first argument. Without going into detail, this makes the predicate succeed when the iteration is complete, if the argument is a list and not a variable (i.e. when it is an input argument). You should have two clauses: one to deal with the empty list and one for the general case:
foo([]). % succeed
foo([X|Xs]) :-
/* apply a predicate to X */
foo(Xs). % apply predicate to the rest of the list
An important thing here is that you don't need a third clause that deals with lists with one element only, since a list with one element is actually a list with an element and an empty list as its tail:
?- [a] == [a|[]].
true.
?- [a] = [a|[]].
true.
Another important thing is that there is nothing you should be doing in the base case, empty list (at least for your example).
To the problem now: your inputs are
the package name
two lists holding pairs of arguments to a predicate you have defined elsewhere (cmp_version/3). This is your list of conditions.
Implementation:
Known packages are available as facts: they can be enumerated by backtracking.
Conditions are an input arguments, provided as a list: you need to apply the condition to each element of the list(s).
The predicate:
check_all([], [], _, _).
check_all([V|Vs], [C|Cs], Name, Version) :-
package(Name, V), % enumerate all known packages by backtracking
cmp_version(Version, V, Cmp), % condition
check_all(Vs, Cs, Name, Version). % apply condition to the rest of the list(s)
You should read the documentation of maplist. You can express the query for example as:
?- maplist(check_version(python), ['3.0', '2.4'], [lt, ge], Versions).
where you have defined a predicate check_version/4 that looks something like:
check_version(Name, V, Cmp, Version) :-
package(Name, Version),
cmp_version(Version, V, Cmp).
As a side note, maplist will reorder its arguments to make it behave like the explicit iteration above.
EDIT
Naming issues, after #mat's comments: one very useful naming convention is to use a name that has descriptive one-word names for the arguments, delimited by underscores. For example, package/2 becomes package_version/2 since its first argument is the package and the second one the version.

Resources