Equating nodes in prolog? - recursion

I'm working on a small function which checks to see if a tree is just a reversed version of another tree.
For example,
1 1
2 3 = 3 2
1 1
My code is just versions of the following:
treeRev(leaf(Leaf1), leaf(Leaf2)) :-
leaf(Leaf1) is leaf(Leaf2).
treeRev(node1(Leaf1, Node1), node1(Leaf2, Node2)) :-
node1(Leaf1,treeRev(Node1)) is node1(Leaf2, treeRev(Node2)).
treeRev(node2(Leaf1, Node1, Node2), node2(Leaf2, Node3, Node4)) :-
node2(Leaf1, treeRev(Node1), treeRev(Node2)) is
node2(Leaf2, treeRev(Node4), treeRev(Node3)).
Where my basis is as following:
Base case is the two leaves are equal, which just returns true. If it has one node, check the leaves are equal, and call the function recursively on the node.
If it's two nodes, check the trees are equal, and then call the recursive function after having flipped the nodes from the second tree.
My issue is, I keep getting the bug
ERROR: is/2: Arithmetic: `leaf/1' is not a function
Thing is, I don't get this error when using other operations on the tree. Any advice on how to get around this? The only limitation imposed is that I can't use =.
I also figured that the most probable cause is that the sides of the is don't return the same "type", according to searches on google and stackoverflow. The way I see it though, is that shouldn't be the case here since I have almost the exact same thing on both ends.
Thank you for reading, and any help is greatly appreciated :)

The is/2 predicate is used for arithmetic. It calculates and assigns the value of an expression (second argument) to the variable-first argument. For example:
X is 1+(2*Y)/2 where Y is already instantiated so it has a value (in order to calculate the value of the expression otherwise it throws instantiation error).
In you case you can't use is/2 since you don't want to calculate any arithmetic expression (that's why the error). What you need is unification, you need to unify a term (e.g a leaf or node) with another term by using =.
For example:
treeRev(leaf(Leaf1), leaf(Leaf2)) :-
leaf(Leaf1) = leaf(Leaf2).
treeRev(node1(Leaf1, Node1), node1(Leaf2, Node2)) :-
node1(Leaf1,treeRev(Node1)) = node1(Leaf2, treeRev(Node2)).
treeRev(node2(Leaf1, Node1, Node2), node2(Leaf2, Node3, Node4)) :-
node2(Leaf1, treeRev(Node1), treeRev(Node2)) =
node2(Leaf2, treeRev(Node4), treeRev(Node3)).
By using pattern matching you could simply do:
treeRev(leaf(Leaf2), leaf(Leaf2)).
treeRev(node1(Leaf2, treeRev(Node2)), node1(Leaf2, Node2)).
treeRev(node2(Leaf2,Node1,Node2), node2(Leaf2, Node3, Node4)):-
treeRev(Node1,Node4),treeRev(Node2,Node3).

... then call the recursive function...
Prolog predicates are not functions. Writing node1(Leaf1,treeRev(Node1)) will not build a node with "the result of calling the treeRev function", as in other programming languages. Instead, Prolog predicates have extra arguments for the "result". You typically call the predicate and bind such "results" to a variable or unify it with a term.
You will need something like this for a binary node (not tested, and not following your teacher's strange and undocumented tree representation):
tree_mirrored(node(LeftTree, RightTree), node(RightMirrored, LeftMirrored)) :-
tree_mirrored(LeftTree, LeftMirrored),
tree_mirrored(RightTree, RightMirrored).

Related

Prolog arithmetic in foreach

So I'm learning Prolog. One of the things I've found to be really obnoxious is demonstrated in the following example:
foreach(
between(1,10,X),
somePredicate(X,X+Y,Result)
).
This does not work. I am well aware that X+Y is not evaluated, here, and instead I'd have to do:
foreach(
between(1,10,X),
(
XPlusY is X + Y,
somePredicate(X, XPlusY, Result)
)
).
Except, that doesn't work, either. As near as I can tell, the scope of XPlusY extends outside of foreach - i.e., XPlusY is 1 + Y, XPlusY is 2 + Y, etc. must all be true AT ONCE, and there is no XPlusY for which that is the case. So I have to do the following:
innerCode(X, Result) :-
XPlusY is X + Y,
somePredicate(X, XPlusY, Result).
...
foreach(
between(1,10,X),
innerCode(X, Result)
).
This, finally, works. (At least, I think so. I haven't tried this exact code, but this was the path I took earlier from "not working" to "working".) That's fine and all, except that it's exceptionally obnoxious. If I had a way of evaluating arithmetic operations in-line, I could halve the lines of code, make it more readable, and NOT create a one-use clutter predicate.
Question: Is there a way to evaluate arithmetic operations in-line, without declaring a new variable?
Failing that, it would be acceptable (and, in some cases, still useful for other things) if there were a way to restrict the scope of new variables. Suppose, for instance, you could define a block within the foreach, where the variables visible from the outside were marked, and any other variables in the block were considered new for that execution of the block. (I realize my terminology may be incorrect, but hopefully it gets the point across.) For example, something resembling:
foreach(
between(1,10,X),
(X, Result){
XPlusY is X + Y,
somePredicate(X, XPlusY, Result)
}
).
A possible solution might be if we can declare a lambda in-line, and immediately call it. Summed up:
Alternate question: Is there a way to limit the scope of new variables within a predicate, while retaining the ability to perform lasting unifications on one or more existing variables?
(The second half I added as clarification in response to an answer about forall.)
A solution to both questions is preferred, but a solution to either will suffice.
library(yall) allows you to define lambda expressions. For instance
?- foreach(between(1,3,X),call([Y]>>(Z is Y+1,writeln(Z)),X)).
2
3
4
true.
Alternatively, library(lambda) provides the construct:
?- [library(lambda)].
true.
?- foreach(between(1,3,X),call(\Y^(Z is Y+1,writeln(Z)),X)).
2
3
4
true.
In SWI-Prolog, library(yall) is autoloaded, while to get library(lambda) you should install the related pack:
?- pack_install(lambda).
Use in alternative the forall/2 de facto standard predicate:
forall(
between(1,10,X),
somePredicate(X,X+Y,Result)
).
While the foreach/2 predicate is usually implemented in the way you describe, the forall/2 predicate is defined as:
% forall(#callable, #callable)
forall(Generate, Test) :-
\+ (Generate, \+ Test).
Note that the use of negation implies that no bindings will be returned when a call to the predicate succeeds.
Update
Lambda libraries allow the specification of both lambda global (aka lambda free) and lambda local variables (aka lambda parameters). Using Logtalk lambdas syntax (available also in SWI-Prolog in library(yall), you can write (reusing Carlo's example) e.g.
?- G = 2, foreach(between(1,3,X),call({G}/[Y]>>(Z is Y+G,writeln(Z)),X)).
3
4
5
G = 2.
?- G = 4, foreach(between(1,3,X),call({G}/[Y]>>(Z is Y+G,writeln(Z)),X)).
5
6
7
G = 4.
Thus, it's possible to use lambdas to limit the scope of some variables within a goal without also limiting the scope of every unification in the goal.

Recursive addition in Prolog

Knowledge Base
add(0,Y,Y). // clause 1
add(succ(X),Y,succ(Z)) :- add(X,Y,Z). // clause 2
Query
add(succ(succ(succ(0))), succ(succ(0)), R)
Trace
Call: (6) add(succ(succ(succ(0))), succ(succ(0)), R)
Call: (7) add(succ(succ(0)), succ(succ(0)), _G648)
Call: (8) add(succ(0), succ(succ(0)), _G650)
Call: (9) add(0, succ(succ(0)), _G652)
Exit: (9) add(0, succ(succ(0)), succ(succ(0)))
Exit: (8) add(succ(0), succ(succ(0)), succ(succ(succ(0))))
Exit: (7) add(succ(succ(0)), succ(succ(0)), succ(succ(succ(succ(0)))))
Exit: (6) add(succ(succ(succ(0))), succ(succ(0)), succ(succ(succ(succ(succ(0))))))
My Question
I see how the recursive call in clause 2 strips the outermost succ()
at each call for argument 1.
I see how it adds an outer succ() to argument 3 at each call.
I see when the 1st argument as a result of these recursive calls
reaches 0. At that point, I see how the 1st clause copies the 2nd
argument to the 3rd argument.
This is where I get confused.
Once the 1st clause is executed, does the 2nd clause automatically
get executed as well, then adding succ() to the first argument?
Also, how does the program terminate, and why doesn't it just keep
adding succ() to the first and 3rd arguments infinitely?
Explanation from LearnPrologNow.com (which I don't understand)
Let’s go step by step through the way Prolog processes this query. The
trace and search tree for the query are given below.
The first argument is not 0 , which means that only the second clause
for add/3 can be used. This leads to a recursive call of add/3 . The
outermost succ functor is stripped off the first argument of the
original query, and the result becomes the first argument of the
recursive query. The second argument is passed on unchanged to the
recursive query, and the third argument of the recursive query is a
variable, the internal variable _G648 in the trace given below. Note
that _G648 is not instantiated yet. However it shares values with R
(the variable that we used as the third argument in the original
query) because R was instantiated to succ(_G648) when the query was
unified with the head of the second clause. But that means that R is
not a completely uninstantiated variable anymore. It is now a complex
term, that has a (uninstantiated) variable as its argument.
The next two steps are essentially the same. With every step the first
argument becomes one layer of succ smaller; both the trace and the
search tree given below show this nicely. At the same time, a succ
functor is added to R at every step, but always leaving the innermost
variable uninstantiated. After the first recursive call R is
succ(_G648) . After the second recursive call, _G648 is instantiated
with succ(_G650) , so that R is succ(succ(_G650) . After the third
recursive call, _G650 is instantiated with succ(_G652) and R therefore
becomes succ(succ(succ(_G652))) . The search tree shows this step by
step instantiation.
At this stage all succ functors have been stripped off the first
argument and we can apply the base clause. The third argument is
equated with the second argument, so the ‘hole’ (the uninstantiated
variable) in the complex term R is finally filled, and we are through.
Let us start by getting the terminology right.
These are the clauses, as you correctly indicate:
add(0, Y, Y).
add(succ(X), Y, succ(Z)) :- add(X, Y, Z).
Let us first read this program declaratively, just to make sure we understand its meaning correctly:
0 plus Y is Y. This makes sense.
If it is true that X plus Y is Z then it is true that the successor of X plus Y is the successor of Z.
This is a good way to read this definition, because it is sufficiently general to cover various modes of use. For example, let us start with the most general query, where all arguments are fresh variables:
?- add(X, Y, Z).
X = 0,
Y = Z ;
X = succ(0),
Z = succ(Y) ;
X = succ(succ(0)),
Z = succ(succ(Y)) .
In this case, there is nothing to "strip", since none of the arguments is instantiated. Yet, Prolog still reports very sensible answers that make clear for which terms the relation holds.
In your case, you are considering a different query (not a "predicate definition"!), namely the query:
?- add(succ(succ(succ(0))), succ(succ(0)), R).
R = succ(succ(succ(succ(succ(0))))).
This is simply a special case of the more general query shown above, and a natural consequence of your program.
We can also go in the other direction and generalize this query. For example, this is a generalization, because we replace one ground argument by a logical variable:
?- add(succ(succ(succ(0))), B, R).
R = succ(succ(succ(B))).
If you follow the explanation you posted, you will make your life very difficult, and arrive at a very limited view of logic programs: Realistically, you will only be able to trace a tiny fragment of modes in which you could use your predicates, and a procedural reading thus falls quite short of what you are actually describing.
If you really insist on a procedural reading, start with a simpler case first. For example, let us consider:
?- add(succ(0), succ(0), R).
To "step through" procedurally, we can proceed as follows:
Does the first clause match? (Note that "matching" is already limited reading: Prolog actually applies unification, and a procedural reading leads us away from this generality.)
Answer: No, because s(_) does not unify with 0. So only the second clause applies.
The second clause only holds if its body holds, and in this case if add(0, succ(0), Z) holds. And this holds (by applying the first clause) if Z is succ(0) and R is succ(Z).
Therefore, one answer is R = succ(succ(0)).. This answer is reported.
Are there other solutions? These are only reported on backtracking.
Answer: No, there are no other solutions, because no further clause matches.
I leave it as an exercise to apply this painstaking method to the more complex query shown in the book. It is straight-forward to do it, but will increasingly lead you away from the most valuable aspects of logic programs, found in their generality and elegant declarative expression.
Your question regarding termination is both subtle and insightful. Note that we must distinguish between existential and universal termination in Prolog.
For example, consider again the most general query shown above: It yields answers, but it does not terminate. For an answer to be reported, it is enough that an answer substitution is found that makes the query true. This is the case in your example. Alternatives, if any potentially remain, are tried and reported on backtracking.
You can always try the following to test termination of your query: Simply append false/0, for example:
?- add(X, Y, Z), false.
nontermination
This lets you focus on termination properties without caring about concrete answers.
Note also that add/3 is a terrible name for a relation: An imperative always implies a direction, but this is in fact much more general and usable also if none of the arguments are even instantiated! A good predicate name should reflect this generality.

Get the name of the calling predicate

Suppose I am working on this toy example (the point of the question is obviously not to solve this example):
p([]).
p([H|T]) :- H = 0, call_predicate(p,T).
call_predicate(Name,Arg) :- call(Name,Arg).
So far so good. Now let's say I want to add a predicate call_predicate/1 where I wouldn't need the name of the predicate:
call_predicate(Arg) :- Name = ??, call(Name,Arg).
So that I could use in p: call_predicate(T), implicitly knowing that I want to call the predicate of the same name.
The question is then how can I retrieve the name p from call_predicate/1, knowing that it is the name of the predicate that called call_predicate/1?
A similar question would be, if it's easier than the first one, how can I retrieve the name of the current predicate I am in at a time in the execution?
In SWI-Prolog check out library(prolog_stack).
In particular, a combination of the following predicates should give you what you want:
get_prolog_backtrace/2
prolog_stack_frame_property/2
Beware though: This is not readily portable to other Prolog systems, and in all likelihood there are more elegant and also more efficient ways to do what you need.
For example, one way to do what you are describing is to use term_expansion/2: You can expand specific goals in such a way that one of the arguments denotes the calling context. This is much more portable, very efficient at run time, and you can statically check the resulting expansion.

Understanding Recursive Rule and Unification in Prolog

I'm a beginning Prolog student following the "LearnPrologNow!" set of tutorials. I'm doing my best to get a grip on the concepts and vocabulary. I've been able to understand everything up until Chapter 3 on Recursive Definitions when presented with this problem:
numeral(0).
numeral(succ(X)) :- numeral(X).
given the query
numeral(X).
Now, I understand that the idea of the program is that Prolog will begin counting numbers in this system in a sequence such as
X=0
X=succ(0)
X=succ(succ(0))
But I do not understand what causes it to "scale back" and ascend each time. I understand the principle of unification in that the program is trying to unify the query of X, but should it just follow the recursive rule once, and then return zero? What allows it to add a succ() around the query? Is that not traversing the recursive rule in the opposite direction?
Please think declaratively:
The rule
numeral(succ(X)) :- numeral(X).
means:
If X is a numeral, then succ(X) is a numeral.
:- is like an arrow used in logical implication (it looks similar to <==).
Seeing that you successfully derived that 0 is a numeral (first answer), it is thus no surprise that succ(0) is another solution.
I recommend you think in terms of such relations, instead of trying to trace the actual control flow.
Notice that succ/1 is not added "around the query", but is a part of the actual answer. The term succ(0) is just a normal Prolog term, with functor succ and argument 0.
Already given answer being good, i'll add some more:
Prolog uses denotational syntax (or declarative syntax) to define logical relations/"equations" between terms
A term is an object comprised of variables/functions/placeholders etc..
Unification is the process to check if two expressions (or two terms) can be equal with respect to the given relations/equations.
numeral(succ(X)) :- numeral(X)
Is such a relation/equation which says that the fact that variable-term X is of numeral type (or class), implies the successor functional succ is also of same type. So Prolog here can unify the expression (in other words solve the equation) and replace X with succ(X) and so on, untill the domain of X is covered. So this unification implies X replaced by succ(X) and then unification can be re-applied.
Just to add a proof tree to this answers, which may make things more clear for others:
Base call: numeral(succ(succ(0))).
: ^
rule1 : : {X/0}
: :
V :
numeral(succ(X)).
: ^
rule1 : : {X/0}
: :
V :
numeral(X).
: ^
fact1 : : {X/0}
: :
V :
Found proof [.]
You start with the downwards arrows and move then back up to the previous calls with the new found unificator in the last step. Please note that Prolog declares each variable in each step as a new variable, which I omitted in this scheme.

How to write a Prolog predicate to split a list into a list of paired elements?

This was a question on a sample exam I did.
Give the definition of a Prolog predicate split_into_pairs that takes as arguments a list and returns as a result a list which consists of paired elements. For example, split_into_pairs([1,2,3,4,5,6],X) would return as a result X=[[1,2],[3,4],[5,6]]. Similarly, split_into_pairs([a,2,3,4,a,a,a,a],X) would return as result X=[[a,2],[3,4],[a,a],[a,a]] while split_into_pairs([1,2,3],X) would return No.
It's not meant to be done using built-in predicates I believe, but it shouldn't need to be too complicated either as it was only worth 8/120 marks.
I'm not sure what it should do for a list of two elements, so I guess that would either be not specified so that it returns no, or split_into_pairs([A,B],[[A,B]]).
My main issue is how to do the recursive call properly, without having extra brackets, not ending up as something like X=[[A,B],[[C,D],[[E,F]]]]?.
My most recent attempts have been variations of the code below, but obviously this is incorrect.
split_into_pairs([A,B],[A,B])
split_into_pairs([A,B|T], X) :- split_into_pairs(T, XX), X is [A,B|XX]
This is a relatively straightforward recursion:
split_into_pairs([], []).
split_into_pairs([First, Second | Tail], [[First, Second] | Rest]) :-
split_into_pairs(Tail, Rest).
The first rule says that an empty list is already split into pairs; the second requires that the source list has at least two items, pairs them up, and inserts the result of pairing up the tail list behind them.
Here is a demo on ideone.
Your solution could be fixed as well by adding square brackets in the result, and moving the second part of the rule into the header, like this:
split_into_pairs([A,B],[[A,B]]).
split_into_pairs([A,B|T], [[A,B]|XX]) :- split_into_pairs(T, XX).
Note that this solution does not consider an empty list a list of pairs, so split_into_pairs([], X) would fail.
Your code is almost correct. It has obvious syntax issues, and several substantive issues:
split_into_pairs([A,B], [ [ A,B ] ] ):- !.
split_into_pairs([A,B|T], X) :- split_into_pairs(T, XX),
X = [ [ A,B ] | XX ] .
Now it is correct: = is used instead of is (which is normally used with arithmetic operations), both clauses are properly terminated by dots, and the first one has a cut added into it, to make the predicate deterministic, to produce only one result. The correct structure is produced by enclosing each pair of elements into a list of their own, with brackets.
This is inefficient though, because it describes a recursive process - it constructs the result on the way back from the base case.
The efficient definition works on the way forward from the starting case:
split_into_pairs([A,B],[[A,B]]):- !.
split_into_pairs([A,B|T], X) :- X = [[A,B]|XX], split_into_pairs(T, XX).
This is the essence of tail recursion modulo cons optimization technique, which turns recursive processes into iterative ones - such that are able to run in constant stack space. It is very similar to the tail-recursion with accumulator technique.
The cut had to be introduced because the two clauses are not mutually exclusive: a term unifying with [A,B] could also be unifiable with [A,B|T], in case T=[]. We can get rid of the cut by making the two clauses to be mutually-exclusive:
split_into_pairs([], [] ).
split_into_pairs([A,B|T], [[A,B]|XX]):- split_into_pairs(T, XX).

Resources