How is suffix/prefix working internally in prolog? - prolog

Can anyone explain how prolog finds a suffix(L1,L2) or prefix(L1,L2) internally?
I know the rule is suffix(L1,L2):- append(_,L2,L1).
But, I can't seem to understand how the variables _, L1 and L2 going inside append and working the query out?
append([],X,X).
append([H|T],Y, [H|W]):- append(T,Y, W).

If you understand append, then the definition
suffix( A, B) :- append( _X, B, A).
is ... well, actually, what is the meaning of append( X, B, A)?
It's that (in pseudocode) [...X, ...B] == A: the list of elements of X, followed by elements of B, together, is the list of elements in A.
This means that B is a (suffix / prefix -- make a choice, please) of A, right? and we don't care what X is. In particular it can be empty, or not.
This explains suffix. For append please see the linked answer, and the answer it links.
This gives us an idea for a follow up question:
Define the predicate proper_suffix(A, B) such that "proper_suffix of A is B" holds, i.e. B is a suffix of A, and B is not the same as A.
You write
I am not understanding how _ for the suffix's argument is going inside append([H|T], Y, [H|W]):- append(T,Y, W). How is append processing the _ for the H of the append to find whether L2 is suffix of L1? if I pass _, how does Prolog figure out the H and T, coz by anonymous variable we mean that 'we don't care about its value' .
So we have
suffix( A, B) :-
append( _X, B,
A).
Whatever the A and B were in the call to suffix(A, B), they will be the same in the call to append( _X, B, A). When that call returns with logic variables _X, A and B holding their (possibly updated) values, the call to suffix returns with its A and B holding those same values as in the append call. The value of _X is not made use of by the suffix/2 predicate, but it is found out just the same, by append/3.
You seem to be confused about the anonymous variable, _. It doesn't matter that it is named that way, it is still a variable. Forget the "don't care" thing, it is confusing and imprecise. Imagine it is named _X, as I showed. it will work exactly the same with _Y, _, Abracadabra, etc., as long as it is not the same as the other variables' names in that rule.
Just one caveat: without the leading _ Prolog will warn us about "singleton variable" i.e. a variable that isn't used anywhere else. It is with respect to this that we signal our intention that "we don't care", with the (leading) _.
Its value is still going to be found, as usual!
And when we use _, the additional convenience is that we don't have to make sure that the name is unique. Each _ is treated as if it were unique, automatically.
You ask (in the comments) how does the query append(_X, [a,b], [1,2,a,b]) work.
Prolog works by choosing a rule whose head matches the query.
This query matches the second clause's head:
append(_X, [a,b], [1,2,a,b]) = append([H|T], Y, [H|W])
with
_X = [H|T], Y = [a,b], [H|W] = [1,2,a,b]
Which also means
H = 1, W = [2,a,b],
and hence
_X = [H|T] = [1|T]
See? This doesn't deconstruct _X, it builds it up!
Since its head matches the query, the second clause of your append definition is thus chosen, and so its body is fired up as the new query under the same substitution, i.e. set of "assignments" to the logic variables involved. So it calls
_X = [H|T], Y = [a,b], [H|W] = [1,2,a,b], append(T,Y,W).
as the new query. That is,
_X = [1|T], Y = [a,b], W = [2,a,b], append(T,Y,W). %% or,
_X = [1|T1], append(T1, [a,b], [2,a,b]).
If we apply the same reasoning, we see again the second clause matching up, and end up with
_X = [1|T1], T1 = [2|T2], append(T2, [a,b], [a,b]).
But now the first clause matches,
append(T2, [a,b], [a,b]) = append([],X,X)
which entails
T2 = [].
Thus
_X = [1|T1]
T1 = [2|T2]
T2 = [].
The list now held by _X has thus been built in a top-down fashion.

Related

How to compare a list of constants to a list of variables

The predicate needs to compare two lists (one of variables, one of constants) like this :
?- test([A,B,B],[1,2,3]).
false.
?- test([A,B,B],[1,2,2]).
true.
?- test([A,B,C],[1,2,2]).
false.
First i associate each variable to its constant with this predicate :
set([],[]).
set([X],[Y]):-X is Y.
set([H1|T1],[H2|T2]):-H1 is H2, set(T1,T2).
It works for the first two exemples above however it doesn't write "true". Also it doesn't work for the third one :
?- set([A,B,C],[1,2,2]).
A = 1,
B = C, C = 2
How do can I modify this predicate so it checks if T1 was already used and in that case if it was associated to a different variable (and therefore return false)?
You can add a dif/2 constraint between every two different variables variables.
We can obtain the list of variables with term_variables/2, and then we can for example design a predicate all_diff/1 that applies dif between every two different variables by making use of maplist/2, like:
all_diff([]).
all_diff([H|T]) :-
maplist(dif(H), T),
all_diff(T).
So we can define our set/2 as:
set(V, W) :-
term_variables(V, VV),
all_diff(VV),
maplist(is, V, W).
The original set/2 can thus be written as maplist/3 with is/2 as goal.
For example:
?- set([A,B,B], [1,2,2]).
A = 1,
B = 2.
?- set([A,B,C], [1,2,2]).
false.
If the second list contains only terms, and you do not want to evaluate expressions, we can - like #DanielLyons says - just use V = W:
set(V, W) :-
term_variables(V, VV),
all_diff(VV),
V = W.
Since the unification algorithm will "peal" the functors, and thus eventually unfiy all elements in the left list with the values in the right list.

Prolog : return variable, check if variable is of certain type?

I am new to Prolog and can't understand predicates very well.
First question: How can I 'return' a certain variable?
We have alternate(?A, ?B). alternate(first, second) should give me back second, and alternate(second, first) should give back first.
Second question: How to check if variable is of certain type?
I have for example ispair(?Pair). I have to check if Pair is pos(X,Y).
Not sure if that's what you meant, but what about the following:
alternate(first, pair(X,_), X).
alternate(second, pair(_,X), X).
If you query without any restrictions, you get the following two answer substitutions:
?- alternate(X,Y,Z).
X = first,
Y = pair(Z, _5844) ; % hit ; to get the second answer
X = second,
Y = pair(_5842, Z). % variables _12345 are fresh ones created by prolog
You can also ask: on which side of the pair (a,b) is b?
?- alternate(Where, pair(a,b), b).
Where = second.
In the case that your pair is (b,b), you get two solutions:
?- alternate(Where, pair(b,b), b).
Where = first ;
Where = second.
Also, c is not part of the pair (a,b):
?- alternate(Where, pair(a,b), c).
false.
If you insist on picking an element from heaven, you will get no as answer:
?- alternate(heaven, X, Y).
false.
When you know that the first element of a pair is a, prolog will tell you how the pair must look like:
?- alternate(first, X, a).
X = pair(a, _5680).
Again we have a fresh variable (_5680) in there, because any second term is fine.

Prolog Set List's Head

append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.

Understanding difference lists (Prolog)

I'm having trouble understanding difference list, particularly in this predicate:
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
Could anyone help me follow what's happening?
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
Seeing the arguments to this predicate as a difference list, the first clause says, a list from A to A (i.e., an empty list) is a palindrome.
The second clause says, a one-element list is a palindrome, whatever that one element is.
Don't panic! Difference lists are just lists with explicit end "pointer"
A normal list, say [1,2,3], is a difference between its start and its end; the end of a normal list is always an empty list, []. That is to say, for a list [1,2,3] we are supposed to call this predicate as palindrome( [1,2,3], []) — namely, check whether the difference list [1,2,3] - [] is a palindrome.
From the operational point of view, a difference list is nothing but a (possibly open-ended) list with explicitly maintained "end pointer", for example: A - Z where A = [1,2,3|Z] and Z = []. Indeed, [1,2,3|[]] is the same as [1,2,3]. But when Z is not instantiated yet, the list A is still open ended - its "end pointer" Z can be instantiated to anything (but only once, of course, sans the backtracking).
If we were to instantiate Z later to an open-ended list, say, Z = [4|W], we'd get a new, extended difference list A - W where A = [1,2,3,4|W]. The old one would become A - Z = [1,2,3,4|W] - [4|W], i.e. still representing a prefix [1,2,3] of an open-ended list [1,2,3,4 ...]. Once closed, e.g. with W = [5], all the pairs of logvars still represent their corresponding difference lists (i.e. A - Z, A - W ...), but A is not open-ended anymore, so can't be extended anymore.
Instead of using the - functor, it is customary to just use both parts of the diff list definition as separate arguments to a predicate. When we always use / treat them as if they were two parts of a pair, then they form a pair, conceptually. It's the same thing.
Continuing. The third clause says, for [C|A]-D to be a palindrome, A-B must be a palindrome, and B must be [C|D]. A, D, B are lists, C is an element of a list. This might be confusing; let's use V instead. Also, use Z and Y instead of D and B, to remind us of "the end" of a list:
palindrome([V|A], Z):- palindrome(A, Y), Y=[V|Z].
V ................. V ----
^ ^ ^
| | |
| | Z
A Y = [V|Z]
Indeed, when the ...... core is a palindrome, putting two Vs around it gives us another palindrome.
The following is a summary that hopefully distills the best of the previous discussion, and adds one small but significant simplification.
First, the original question should be understood in the context of the problem at hand, which can be formulated as defining a Prolog predicate which will check whether a list is a palindrome, or more generally to generate palindromes. We wish to explore an implementation using difference lists, so we can begin as follows:
% List is a palindrome if List - [] is a palindrome:
palindrome( List ) :- palindrome(List, []).
(As explained elsewhere, if a list, List, is the concatenation of two lists
Front and Back, then Front can be viewed as being the difference
between List and Back, that is, Front can be regarded as equivalent to (List - Back).)
To define palindrome/2, we begin with the two "base cases", an empty list and a singleton:
% The empty list (L-L) is a palindrome:
palindrome(L, L).
% A singleton list, ([X|L] - L), is a palindrome:
palindrome([X|L], L).
Let us now turn to the general case.
If a list with more than one element is to be a palindrome, then it
will look like this: E ... E
where ... is a (possibly empty) palindrome.
Tacking on a tail, Tail, our list must look like: E ... E Tail
Writing this regular list as [E|Rest], we can now see that the original list ( [E|Rest] - Tail ) is a palindrome if (Rest - [E|Tail]) is a palindrome,
or in terms of our predicate palindrome/2:
palindrome( [E|Xs], Tail ) :- palindrome(Xs, [E|Tail]).
It's easy to see that this is equivalent to the original formulation.
That's it! Now we can, for example, generate templates for palindromes:
?- palindrome( X ).
X = [] ;
X = [_G1247] ;
X = [_G1247, _G1247] ;
X = [_G1247, _G1253, _G1247] ;
X = [_G1247, _G1253, _G1253, _G1247]
....

Prolog - how to understand lists

I don't know much, how to understand that fact p([H|T], H, T). I know C/C++/Java etc.. but this looks diferrent. So when i pass first argument to "function" p, it separates it into H and T and makes it accessible through this vars? I don't know how to logically understand this.
http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/lists.html
p([H|T], H, T).
Lets see what happens when we ask some simple queries.
?- p([a,b,c], X, Y).
X=a
Y=[b,c]
yes
In Prolog we have relations, in a way similar to relationals DBs.
Then p/3 it's a relation among a list (first argument), its head H and its tail T.
Appropriately the tutorial' author used descriptive and synthetic symbols as Variables.
Syntactically, variables are symbols starting Uppercase and can get any value, but only one time (that is, cannot be 'reassigned').
The page you refer to says, "Consider the following fact.
p([H|T], H, T)."
So we must treat this as a fact. That means, it's like having a predicate
p([H|T], H, T):- true. % or, p(L,H,T) :- L=[H|T].
Now, when you query p([a,b,c], X, Y)., one is put besides the other:
p([a,b,c], X, Y). % a query
p([H|T], H, T) :- true. % a rule's clause: _head_ :- _body_.
the equivalences are noted: [a,b,c] = [H|T], X = H, Y = T and treated as unification equations. The first gets further translated into
a = H % list's head element
[b,c] = T % list's tail
because [A|B] stands for a list with A the head element of the list, and B the list's tail, i.e. all the rest of its elements, besides the head. H and T are common mnemonic names for these logical variables.
So on the whole, we get X = H = a, Y = T = [b,c].
This process is what's known as unification of a query and a rule's head (the two things starting with a p "functor", and both having the 3 "arguments").
Since the query and the head of a rule's "clause" matched (had same functor and same number of arguments), and their arguments were all successfully unified, pairwise, using the above substitution, we only need to prove the body of that rule's clause (that was thus selected).
Since it is true, we immediately succeed, with the successful substitution as our result.
That's how Prolog works.
TL;DR: yes, when you call p(L,H,T) with a given list L, it will be destructured into its head H and tail T. But you may call it with a given list T, a value H, and a variable L, and then a new list will be constructed from the head and the tail. And if L is given as well, it will be checked whether its head is H, and its tail is T.
This is because Prolog's unification is bi-directional: A = B is the same as B = A. Unification with a variable is like setting that variable, and unification with a value is like checking the (structural) equality with that value.
Calling p(L,H,T) is really equivalent to the unification L = [H|T].

Resources