Convert Prolog functor to functor with difference lists - prolog

I'm working on my homework for Prolog (SWI) but can't figure out how to get this done:
I have the functor:
palindrome([]).
palindrome([_]).
palindrome([A|T]) :-
append(Middle,[A],T),
palindrome(Middle).
which tells if a given list is a palindrome.
For my homework I have to write a functor palindrome/2 without append/3 and with difference lists.
I know a difference list is a form of [Y|X]-X, but I don't understand how to use this and how this can replace the append functor.
Can somebody please explain this to me?

For a given list of length n, your solution needs some O(n2) inferences: n (actually n/2) for palindrome/1 and i for each append/3 which simply searches and compares the end.
The most straight forward way to reformulate your definition uses grammars (DCGs) that are a convenient way to use difference-lists. Note that each grammar rule corresponds to a clause in your program.
palindrome -->
[].
palindrome -->
[_].
palindrome -->
[A],
palindrome,
[A].
palindrome(T) :-
phrase(palindrome,T).
For convenience, here is the same grammar written more compactly:
palindrome --> [] | [_] | [A], palindrome, [A].
Now, how are these grammar rules implemented? The easiest way is to look at the actual definition with listing(palindrome).
?- listing(palindrome).
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
So this is now your definition using difference-lists.

Just write it down yourself. You have
palindrome([]). % palindrome(Z-Z).
palindrome([_]). % palindrome([_|Z]-Z).
palindrome([A|T]) :- % palindrome([A|T]-Z):-
append(Middle,[A],T), % append(Middle-Z2,[A|Z3]-Z3,T-Z),
palindrome(Middle). % palindrome(Middle-Z2).
Append for dif-lists is append(A-B,B-C,A-C), so the append call gives us Z2=[A|Z3], Z3=Z, Middle=T, and so (writing out the two halves of a dif-list as two arguments for the predicate),
palindrome(Z,Z).
palindrome([_|Z],Z).
palindrome([A|T],Z) :-
palindrome(T, [A|Z]).
Now you can run it
10 ?- palindrome(X,[]).
X = [] ;
X = [_G340] ;
X = [_G340, _G340] ;
X = [_G340, _G346, _G340] ;
X = [_G340, _G346, _G346, _G340] ;
....
11 ?- X=[a,b,c|_],palindrome(X,[z]).
X = [a, b, c, b, a, z] ;
X = [a, b, c, c, b, a, z] ;
X = [a, b, c, _G460, c, b, a, z] ;
X = [a, b, c, _G460, _G460, c, b, a, z] ;
....
16 ?- palindrome([1,2,2,1,0],Z).
Z = [1, 2, 2, 1, 0] ;
Z = [2, 2, 1, 0] ;
Z = [0] ;
No
Of course, DCG rules provide a comfortable interface to difference-lists.

Related

Equality of sets

Can anyone help me with the following task: I need to define a predicate eq_set, which succeeds if the sets S1 and S2 are equal when it comes to the number of their elements.
But it works only if they are exactly the same number and order. I want to create a code that shows all varieties and doesn't take order into account. Can you help me,please?
I wrote:
eq_set([],[]).
eq_set([H|T],[H|T1]) :-
eq_set(T,T1).
But it works only if they are exactly the same number and order. I want to create a code that shows all varieties and doesn't take order into account.
The closest translation I have of the assignment, which is in Bulgarian, is: "Define the predicate eq_set, which succeeds if the sets (S1, S2) coincide.
You call them "sets" but the data structure you are using is a list. It is easiest to just sort the two lists:
eq_set(A, B) :-
% prerequisites: A and B are lists without duplicates
sort(A, S),
sort(B, S).
If you want something more complicated (for some reason) you need to be more specific.
With this definition:
?- eq_set([a,b,c], [a,b]).
false. % OK
?- eq_set([a,b,c], [a,b,c]).
true. % OK
?- eq_set([a,c,b], [a,b,c]).
true. % OK
?- eq_set([a,a,b], [a,b,b]).
true. % Not sure....
It really really depends on how the predicate is going to be used.
Assuming that a "set" is indeed a Prolog list without duplicates but not in any particular order; then two sets in that presentation "coincide" if they are permutations of each other. In other words, it would be enough to define eq_set/2 as:
eq_set(A, B) :-
my_permutation(A, B).
and just use the textbook definition of permutation/2 which uses the textbook definition of select/3 (See "The Art of Prolog (Second Edition)" by Sterling and Shapiro, pp 67-9):
my_permutation([], []).
my_permutation(Xs, [Y|Ys]) :-
my_select(Y, Xs, Xs0),
my_permutation(Xs0, Ys).
my_select(X, [X|Xs], Xs).
my_select(X, [Y|Ys], [Y|Zs]) :-
my_select(X, Ys, Zs).
(I renamed those just to make sure I am not using the standard library definitions; SWI-Prolog has both select/3 and permutation/2 in the autoloaded library(lists); the definitions are basically the same, but they do some run-time type-checking on the arguments.)
Here is how you can use it:
?- eq_set([1,2,3], [2,3,1]).
true ;
false.
?- eq_set([1,2,3], S).
S = [1, 2, 3] ;
S = [1, 3, 2] ;
S = [2, 1, 3] ;
S = [2, 3, 1] ;
S = [3, 1, 2] ;
S = [3, 2, 1] ;
false.
?- eq_set([1,2,3], [1,2]).
false.
?- eq_set(A, B).
A = B, B = [] ;
A = B, B = [_4480] ;
A = B, B = [_4480, _4492] ;
...
I am not sure how useful the last query is. You can force it to enumerate solutions in order of increasing size of the "set", like this:
?- length(S1, _), eq_set(S1, S2), numbervars(S1).
S1 = S2, S2 = [] ;
S1 = S2, S2 = [A] ;
S1 = S2, S2 = [A, B] ;
S1 = [A, B],
S2 = [B, A] ;
S1 = S2, S2 = [A, B, C] ;
S1 = [A, B, C],
S2 = [A, C, B] ;
S1 = [A, B, C],
S2 = [B, A, C] ;
S1 = [A, B, C],
S2 = [B, C, A] ;
S1 = [A, B, C],
S2 = [C, A, B] ;
S1 = [A, B, C],
S2 = [C, B, A] ;
S1 = S2, S2 = [A, B, C, D] .
(Don't worry about the numbervars, it is just there to give readable names to all the free variables in the sets. Keep in mind that unifying two free variables makes them the same variable.)
This is a starting point, but maybe it is already good enough. The most glaring omission is that it doesn't require the arguments to be lists without duplicates. One way to define this would be to require that each element is different from all other elements. Since "is different" is commutative, you can define it like this:
is_set([]).
is_set([X|Xs]) :-
all_different(Xs, X),
is_set(Xs).
all_different([], _).
all_different([Y|Ys], X) :-
dif(X, Y),
all_different(Ys, X).
This uses dif/2 which is a widely available predicate (but does your Prolog have it?).
We would have maybe used maplist for that last one:
is_set([]).
is_set([X|Xs]) :-
maplist(dif(X), Xs).
is_set(Xs).
You are pretty close in your solution.
We have two cases
1) The first list argument is bigger
2) The second list argument is bigger
If you already know which one is bigger, you can just do
%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).
So a very simple solution and yet very optimal could be this:
%in case the right one is longer
eq_set_right([],_).
eq_set_right([H|T], X):- member(H,X), eq_set_right(T,X).
%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).
%both cases, equal length is also included here
eq_set(X,Y):- eq_set_left(X,Y).
eq_set(X,Y):- eq_set_right(X,Y).
eq_set(X, Y) is true if either X is subset of Y, Y is subset of X or they are equal
A set is defined as a collection of distinct things where order is not important, which is to say that sets {a,b,c} and {b,a,c} are identical.
From that, one could say that two sets are identical if neither set contains an element that is not also found in the other (or conversely, two sets are not identical if either set contains an element not found in the other.
From that, one could simply say:
eq_set(Xs,Ys) :-
findall( (Xs,Ys) , ( member(X,Xs), \+ member(X,Ys) ), [] ),
findall( (Xs,Ys) , ( member(Y,Ys), \+ member(Y,Xs) ), [] )
.
Or if you don't want to use the built-in findall/3,
eq_set(Xs,Ys) :-
a_not_in_b( Xs , Ys , [] ) ,
a_not_in_b( Ys , Xs , [] ) .
a_not_in_b( [] , [] , [] ) .
a_not_in_b( [A|As] , Bs , Xs ) :- member(A,Bs) , a_not_in_b( As, Bs, Xs ) .
a_not_in_b( [A|As] , Bs , Xs ) :- a_not_in_b( As, Bs, [A|Xs] ) .
One should note that both of these has roughly O(N2) performance. If the sets in question are large, you might want to first sort each set and then merge the two sorted lists to identify those elements that are not common to both sets:
eq_set(Xs,Ys) :-
sort(Xs,X1),
sort(Ys,Y1),
X1 == Y1.

Prolog Out of stack error

I'm working on Problem 26 from 99 Prolog Problems:
P26 (**) Generate the combinations of K distinct objects chosen from
the N elements of a list
Example:
?- combination(3,[a,b,c,d,e,f],L).
L = [a,b,c] ;
L = [a,b,d] ;
L = [a,b,e] ;
So my program is:
:- use_module(library(clpfd)).
combination(0, _, []).
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length,
append(Prefix, [H], Stem),
append(Stem, Suffix, List),
append(Prefix, Suffix, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
My query result starts fine but then returns a Global out of stack error:
?- combination(3,[a,b,c,d,e,f],L).
L = [a, b, c] ;
L = [a, b, d] ;
L = [a, b, e] ;
L = [a, b, f] ;
Out of global stack
I can't understand why it works at first, but then hangs until it gives Out of global stack error. Happens on both SWISH and swi-prolog in the terminal.
if you try to input, at the console prompt, this line of your code, and ask for backtracking:
?- append(Prefix, [H], Stem).
Prefix = [],
Stem = [H] ;
Prefix = [_6442],
Stem = [_6442, H] ;
Prefix = [_6442, _6454],
Stem = [_6442, _6454, H] ;
...
maybe you have a clue about the (main) problem. All 3 vars are free, then Prolog keeps on generating longer and longer lists on backtracking. As Boris already suggested, you should keep your program far simpler... for instance
combination(0, _, []).
combination(Tot, List, [H|T]) :-
Tot #> 0,
select(H, List, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
that yields
?- aggregate(count,L^combination(3,[a,b,c,d,e],L),N).
N = 60.
IMHO, library(clpfd) isn't going to make your life simpler while you're moving your first steps into Prolog. Modelling and debugging plain Prolog is already difficult with the basic constructs available, and CLP(FD) is an advanced feature...
I can't understand why it works at first, but then hangs until it gives Out of global stack error.
The answers Prolog produces for a specific query are shown incrementally. That is, the actual answers are produced lazily on demand. First, there were some answers you expected, then a loop was encountered. To be sure that a query terminates completely you have to go through all of them, hitting SPACE/or ; all the time. But there is a simpler way:
Simply add false at the end of your query. Now, all the answers are suppressed:
?- combination(3,[a,b,c,d,e,f],L), false.
ERROR: Out of global stack
By adding further false goals into your program, you can localize the actual culprit. See below all my attempts: I started with the first attempt, and then added further false until I found a terminating fragment (failure-slice).
combination(0, _, []) :- false. % 1st
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length, % 4th terminating
append(Prefix, [H], Stem), false, % 3rd loops
append(Stem, Suffix, List), false, % 2nd loops
append(Prefix, Suffix, SubList),
SubTot #= Tot-1, false, % 1st loops
combination(SubTot, SubList, T).
To remove the problem with non-termination you have to modify something in the remaining visible part. Evidently, both Prefix and Stem occur here for the first time.
The use of library(clpfd) in this case is very suspicious. After length(List, Length), Length is definitely bound to a non-negative integer, so why the constraint? And your Tot in 1..Length is weird, too, since you keep on making a new constrained variable in every step of the recursion, and you try to unify it with 0. I am not sure I understand your logic overall :-(
If I understand what the exercise is asking for, I would suggest the following somewhat simpler approach. First, make sure your K is not larger than the total number of elements. Then, just pick one element at a time until you have enough. It could go something like this:
k_comb(K, L, C) :-
length(L, N),
length(C, K),
K =< N,
k_comb_1(C, L).
k_comb_1([], _).
k_comb_1([X|Xs], L) :-
select(X, L, L0),
k_comb_1(Xs, L0).
The important message here is that it is the list itself that defines the recursion, and you really don't need a counter, let alone one with constraints on it.
select/3 is a textbook predicate, I guess you should find it in standard libraries too; anyway, see here for an implementation.
This does the following:
?- k_comb(2, [a,b,c], C).
C = [a, b] ;
C = [a, c] ;
C = [b, a] ;
C = [b, c] ;
C = [c, a] ;
C = [c, b] ;
false.
And with your example:
?- k_comb(3, [a,b,c,d,e,f], C).
C = [a, b, c] ;
C = [a, b, d] ;
C = [a, b, e] ;
C = [a, b, f] ;
C = [a, c, b] ;
C = [a, c, d] ;
C = [a, c, e] ;
C = [a, c, f] ;
C = [a, d, b] ;
C = [a, d, c] ;
C = [a, d, e] ;
C = [a, d, f] ;
C = [a, e, b] ;
C = [a, e, c] . % and so on
Note that this does not check that the elements of the list in the second argument are indeed unique; it just takes elements from distinct positions.
This solution still has problems with termination but I don't know if this is relevant for you.

I want to create two Prolog relations and place their definitions in a single Prolog file

I want to create two Prolog relations and place their definitions in a single Prolog file. Define the relations prefix and postfix on lists, meaning that the first argument is a prefix or postfix, respectively, of the second.
?- consult(prepost).
% prepost compiled 0.00 sec, 956 bytes
true.
?- prefix([a,b,c],[a,b,c,e,f]).
true.
?- prefix([a,b,c], [a,b,e,f]).
false.
?- prefix([a,b],[a]).
false.
?- prefix([],[a,b,c,d]).
true.
?- prefix(X,[a,b,c,d]).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, c] ;
X = [a, b, c, d] ;
false.
?- postfix([n,e],[d,o,n,e]).
true .
?- postfix([],[a,n,y,t,h,i,n,g]).
true .
?- postfix([a,b,c],[a,b,c,d,e]).
false.
?- postfix(X,[a,b,c,d]).
X = [a, b, c, d] ;
X = [b, c, d] ;
X = [c, d] ;
X = [d] ;
X = [] ;
false.
?-
You can use the predicate append/3 to solve your problem in a simple way.
A list of elements is prefix of some other list, if there is a combination where this first list concatenated with another (not relevant), results in your full list.
prefix(Prefix_list, Full_list):- append(Prefix_list, _, Full_list).
You can infer your predicate postfix/2 in the same way:
postfix(Postfix_list, Full_list):- append(_, Postfix_list, Full_list).
Now, put both predicate in a text file, name it prepost.pl, and that's it.

Prolog program to recognize context free grammar a^n b^n

Using Prolog I'm trying to write a predicate that recognizes context free grammar and returns true if the input list matches the CFG.
The alphabet of the input consists only of a,b.
The CFG i'm trying to match is
S-> TT
T -> aTb | ab
I'm not quite sure how to implement this, mainly the T rule.
s(S0,S):-t(S0,S),t(S1,S).
t(S0,S):-S0 = a, t(S1,S), S1 = b; S0 = a, S1 = b.
match([H|T] :- s(H,T).
So if I query [a, a, b, b] it should return true.
However, I'm just getting an infinite loop.
I'm not quite sure how to implement the a^n b^n rule.
I would write the CFG in this way:
S -> T
T -> a T b | {epsilon}
that translates directly to a DCG:
s --> t.
t --> [].
t --> a, t, b.
Note I swapped the epsilon rule, to get the ability to generate phrases.
Translating that DCG by hand :
s(S0,S) :- t(S0,S).
t(S0,S0).
t(S0,S) :- S0=[a|S1], t(S1,S2), S2=[b|S].
Yields
?- phrase(s,L).
L = [] ;
L = [a, b] ;
L = [a, a, b, b] ;
L = [a, a, a, b, b, b] ;
...

Passing the Results of a Prolog Predicate

How does one evaluate the result of a prolog predicate to pass as an argument?
I am trying to write code to reverse pairs of elements in a list:
swap([A,B,C,D,E,F],R).
I want the result:
[B,A,D,C,F,E]
but I get this result:
append(append(append([],[B,A],[D,C],[F,E])))
Here is my code:
swap(L,R) :- swapA(L,[],R).
swapA([],A,A).
swapA([H,H2|T],A,R) :- swapA(T, append(A,[H2,H]), R).
Thanks.
Several things:
a variable starts with a capital letter, if you want to differenciate an atom from a variable, wrap it between ': ['A','B','C','D','E','F']
you do not need append to successfully implement this predicate. The complexity is way worse when using append.
because you do not need append, you do not need 3 arguments either, 2 suffice
Here is a suggestion:
swapA([], []).
swapA([X, Y|T], [Y, X|R]) :- swapA(T, R).
And consider adding another base case if you want your predicate to hold when you have an odd number of elements in your list:
swapA([X], [X]).
You can't call a Prolog predicate like a function. It doesn't return anything. When you pass append(A,[H2,H]) to swap, it interprets it as data, not as code.
A Prolog clause creates a relation between N logic variables. That means in theory there is no concept of "input" and "output" in Prolog predicates, you can make a query with any combination of instantiated and non-instantiated variables, and the language will find the meaningful relation(s) for you:
1 ?- append([a],[b,c],[a,b,c]).
true.
2 ?- append([a],[b,c],Z).
Z = [a, b, c].
3 ?- append([a],Y,[a,b,c]).
Y = [b, c].
4 ?- append(X,[b,c],[a,b,c]).
X = [a] ;
false.
5 ?- append([a],Y,Z).
Z = [a|Y].
6 ?- append(X,[b,c],Z).
X = [],
Z = [b, c] ;
X = [_G383],
Z = [_G383, b, c] ;
X = [_G383, _G389],
Z = [_G383, _G389, b, c] . % etc
7 ?- append(X,Y,[a,b,c]).
X = [],
Y = [a, b, c] ;
X = [a],
Y = [b, c] ;
X = [a, b],
Y = [c] ;
X = [a, b, c],
Y = [] ;
false.
8 ?- append(X,Y,Z).
X = [],
Y = Z ;
X = [_G362],
Z = [_G362|Y] ;
X = [_G362, _G368],
Z = [_G362, _G368|Y] . % etc
9 ?-
In practice, not every predicate can be called with every combination, due to limitations in expressing the relation in a way that will not yield an infinite loop. Other cause may be extra-logic features, like arithmetic. When you see a predicate documented like:
pred(+Foo, -Bar, ?Baz)
That means it expects Foo to be instantiated (i.e. unified to another non-var), Bar to be a free variable and Baz can be anything. The same predicate can have more than one way to call it, too.
This is the reason you can't treat a Prolog relation as a function, in general. If you pass a compound as argument, the clauses will likely treat it just as a compound, unless it is specifically designed to handle it as code. One example is call/1, which executes its argument as code. is, =:=, < and other arithmetic operators do some interpretation too, in case you pass something like cos(X).

Resources