Palindrome (homework) - list

I tried to write a Prolog program by using lists. However, I have to use difference lists and output should be:
The ith element of the list is the same of (n-i+1)th element of the list and n is the length of the list. For example, [a,X,c,b,Y] should give X = b and Y = a. I could not find similar palindrome example in other questions.
So far I have implemented:
% length of the list
len([], 0).
len([H|T], B) :-
len(T, NT),
B is NT + 1.
% return the ith element of the list
match([H|_], 0, H) :-
!.
match([_|T], N, H) :-
N > 0,
N1 is N-1,
match(T, N1, H).
However, I could not complete. Please help me!

Use definite clause grammars!
DCG, a major Prolog feature, makes using difference lists easy—enabling you to write concise and efficient code with little effort!
Want to know more? Just follow the dots:
DCG has its own tag on StackOverflow, dcg.
en.wikipedia.org has an extensive article on DCG.
For a jumpstart, read the DCG primer by Markus Triska!
Without any further ado, let's get to the code:
palindrome --> [].
palindrome --> [_].
palindrome --> [X], palindrome, [X].
% Alternatively, we could also use the following more compact definition:
palindrome --> [] | [_] | [X], palindrome, [X].
Done. Let's run a few queries! First, the query the OP gave:
?- phrase(palindrome, [a,X,c,b,Y]).
X = b, Y = a
; false.
In German, "corn" is called "mais". If we put "siam" (the old name of "the Kingdom of Thailand") in front, we get a delicious palindrome:
?- set_prolog_flag(double_quotes, chars).
true.
?- phrase(palindrome, "siammais").
true
; false.
?- phrase(palindrome, "siamais"). % or kick one middle 'm' character
true % ... for an odd-length palindrome
; false.
At last, let's not forget about the most general query:
?- phrase(palindrome, Xs).
Xs = []
; Xs = [_A]
; Xs = [_A,_A]
; Xs = [_A,_B,_A]
; Xs = [_A,_B,_B,_A]
; Xs = [_A,_B,_C,_B,_A]
...
On the prolog-toplevel we can use the built-in Prolog predicate listing/1 to peek at the code the DCG was "translated" to—at this level the internal use of difference-lists becomes apparent:
?- listing(palindrome//0).
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B = [C|D].
true.

Related

Prolog Finding middle element in List

I am trying to make use of prolog predicates and find middle element of a given list. My idea was to cut first and last element of list using recursion.Unfortunately I dont know how to handle recursion call properly.
delete_last(L, L1) :-
append(L1, [_], L).
delete_first(L,L1) :-
append([_],L1,L).
check_len(L) :-
length(L,LEN), \+ 1 is LEN.
delete_both([],_):-
false.
delete_both([_,_],_) :-
false.
delete_both([X],X):-
true, write('MidElement').
delete_both(L,L2) :-
delete_first(LT,L2), delete_last(L,LT),check_len(LT)
->write('here should be recursive call only when length is more than one').
I would be grateful for any help.
It would save a lot of typing if you checked the length of the list, calculated the position of the middle element, and only then traversed the list to get the element at that position. With SWI-Prolog, this would be:
?- length(List, Len),
divmod(Len, 2, N, 1),
nth0(N, List, a).
List = [a], Len = 1, N = 0 ;
List = [_G2371, a, _G2377], Len = 3, N = 1 ;
List = [_G2371, _G2374, a, _G2380, _G2383], Len = 5, N = 2 . % and so on
This solution makes sure the list has an odd length. You can see the documentation of divmod/4 if you need to define it yourself. Or, if the list does not have to have and odd, length, just use N is Len div 2. If for some reason you are not allowed to use nth0/3, it is still an easier predicate to implement than what you are trying to do.
You can tighten up what you have quite a bit as follows:
delete_last(L, L1) :-
append(L1, [_], L).
delete_first([_|L], L).
% No need to check length of 1, since we only need to check
% if L = [X] in the caller, so we'll eliminate this predicate
%check_len(L) :-
% length(L, 1). % No need for an extra variable to check length is 1
% Clauses that yield false are not needed since clauses already fail if not true
% So you can just remove those
%
delete_both([X], X) :-
write('MidElement').
% Here you need to fix the logic in your main clause
% You are deleting the first element of the list, then the last element
% from that result and checking if the length is 1.
delete_both(L, X) :-
delete_first(L, L1), % Remove first and last elements from L
delete_last(L1, LT),
( LT = [X] % Check for length of 1
-> true
; delete_both(LT, X) % otherwise, X is result of delete_both(LT, X)
).
With results:
| ?- delete_both([a,b,c,d,e], X).
X = c
yes
| ?- delete_both([a,b,c,d,e,f], X).
no
A DCG solution also works well here:
% X is the middle if it is flanked by two sequences of the same length
%
middle(X) --> seq(N), [X], seq(N).
seq(0) --> [].
seq(N) --> [_], { N #= N1 + 1 }, seq(N1).
middle(List, X) :- phrase(middle(X), List).
With results:
| ?- middle([a,b,c,d,e], X).
X = c ? ;
(1 ms) no
| ?- middle(L, a).
L = [a] ? ;
L = [_,a,_] ? ;
L = [_,_,a,_,_] ?
...
Another possible solution is to use SWI Prolog's append/2 predicate, which appends a list of lists (assuming you're using SWI):
middle(L, X) :-
same_length(Left, Right),
append([Left, [X], Right], L).
same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).
In all of the above solutions, the predicate fails if the list has an even number of elements. Since that's what your original solution does, I assumed that's what is required. If there is a specific requirement for even lists, that needs to be stated clearly.

Excluding all occurrences of the minimum number in a list

As a Prolog newbie, I try to define a predicate filter_min/2 which takes two lists to determine if the second list is the same as the first, but with all occurrences of the minimum number removed.
Sample queries with expected results:
?- filter_min([3,2,7,8], N).
N = [3,7,8].
?- filter_min([3,2,7,8], [3,7,8]).
true.
I tried but I always get the same result: false. I don't know what the problem is. I need help!
Here is my code:
filter_min(X,Y) :-
X == [],
write("ERROR: List parameter is empty!"),
!;
min_list(X,Z),
filter(X,Y,Z).
filter([],[],0).
filter([H1|T1],[H2|T2],Z) :-
\+ number(H1),
write("ERROR: List parameter contains a non-number element"),
!;
H1 \= Z -> H2 is H1, filter(T1,T2,Z);
filter(T1,T2,Z).
There are a couple of problems with your code:
filter([],[],0). will not unify when working with any list that does not have 0 as its minimum value, which is not what you want. You want it to unify regardless of the minimum value to end your recursion.
The way you wrote filter([H1|T1],[H2|T2],Z) and its body will make it so that the two lists always have the same number of elements, when in fact the second one should have at least one less.
A correct implementation of filter/3 would be the following:
filter([],[],_).
filter([H1|T1],L2,Z):-
\+ number(H1),
write("ERROR: List parameter contains a non-number element"),
!;
H1 \= Z -> filter(T1,T2,Z), L2 = [H1|T2];
filter(T1,L2,Z).
A bounty was offered...
... for a pure solution that terminates for (certain) cases where neither the length of the first nor of the second argument is known.
Here's a candidate implementation handling integer values, built on clpfd:
:- use_module(library(clpfd)).
filter_min(Xs,Ys) :-
filter_min_picked_gt(Xs,_,false,Ys).
filter_min_picked_gt([] ,_,true ,[]).
filter_min_picked_gt([Z|Xs],M,Picked,[Z|Zs]) :-
Z #> M,
filter_min_picked_gt(Xs,M,Picked,Zs).
filter_min_picked_gt([M|Xs],M,_,Zs) :-
filter_min_picked_gt(Xs,M,true,Zs).
Some sample queries:
?- filter_min([3,2,7,8],[3,7,8]).
true ; false. % correct, but leaves choicepoint
?- filter_min([3,2,7,8],Zs).
Zs = [3,7,8] ; false. % correct, but leaves choicepoint
Now, some queries terminate even though both list lengths are unknown:
?- filter_min([2,1|_],[1|_]).
false. % terminates
?- filter_min([1,2|_],[3,2|_]).
false. % terminates
Note that the implementation doesn't always finitely fail (terminate) in cases that are logically false:
?- filter_min([1,2|_],[2,1|_]). % does _not_ terminate
For a Prolog newbie, better start with the basics. The following works when first argument is fully instantiated, and the second is an uninstantiated variable, computing the result in one pass over the input list.
% remmin( +From, -Result).
% remmin([],[]). % no min elem to remove from empty list
remmin([A|B], R):-
remmin(B, A, [A], [], R). % remove A from B to get R, keeping [A]
% in case a smaller elem will be found
remmin([C|B], A, Rev, Rem, R):-
C > A -> remmin(B, A, [C|Rev], [C|Rem], R) ;
C==A -> remmin(B, A, [C|Rev], Rem, R) ;
C < A -> remmin(B, C, [C|Rev], Rev, R).
remmin([], _, _, Rem, R) :- reverse(Rem, R).
First, we can get the minimum number using the predicate list_minnum/2:
?- list_minnum([3,2,7,8],M).
M = 2.
We can define list_minnum/2 like this:
list_minnum([E|Es],M) :-
V is E,
list_minnum0_minnum(Es,V,M).
list_minnum0_minnum([],M,M).
list_minnum0_minnum([E|Es],M0,M) :-
M1 is min(E,M0),
list_minnum0_minnum(Es,M1,M).
For the sake of completeness, here's the super-similar list_maxnum/2:
list_maxnum([E|Es],M) :-
V is E,
list_maxnum0_maxnum(Es,V,M).
list_maxnum0_maxnum([],M,M).
list_maxnum0_maxnum([E|Es],M0,M) :-
M1 is max(E,M0),
list_maxnum0_maxnum(Es,M1,M).
Next, we use meta-predicate tfilter/3 in tandem with dif/3 to exclude all occurrences of M:
?- M=2, tfilter(dif(M),[2,3,2,7,2,8,2],Xs).
Xs = [3,7,8].
Put the two steps together and define min_excluded/2:
min_excluded(Xs,Ys) :-
list_minnum(Xs,M),
tfilter(dif(M),Xs,Ys).
Let's run some queries!
?- min_excluded([3,2,7,8],Xs).
Xs = [3,7,8].
?- min_excluded([3,2,7,8,2],Xs).
Xs = [3,7,8].

Searching a list for (same) two elements in Prolog

How can I search a list in Prolog for a specific element that appears more than once?
For example, if we are searching the list [1,2,3,4,1] for the element 1, Prolog should return true, but otherwise false for all other numbers.
This is what I have so far:
duplicate([], _) :-
false,
!.
duplicate([X|_], X) :-
true,
!.
duplicate([H|T], X) :-
T = [_|T1],
duplicate(T, X),
duplicate(T1, X).
My basic idea is to search the list until I find the element I am looking for, then search the tail of the list for the item again. I do not want to use the member() function provided by Prolog.
Prolog should also return the elements that appear more than once if asked by the query: duplicate([1,2,3,4,1], X), should print X = 1.
And here the obvious version using grammars. In a sense, we are describing the structure of a list containing a duplicate. That structure is as follows:
First, there is anything (...),
then there is the element ([V]),
again anything (...)
and again the element ([V])
followed by anything.
duplicate(L, V) :-
phrase(( ..., [V], ..., [V], ... ), L).
... --> [] | [_], ... .
As a downside, this version will produce redundant answers for a query like
?- duplicate([a,a,a],a).
This can be overcome by using dif/2:
duplicate(L, V) :-
phrase(( all(dif(V)), [V], all(dif(V)), [V], ... ), L).
The definition for non-terminal all//1.
What I was saying in my comment was : I want two items from the list L wich are not in the same place so
duplicate(L, V) :-
% nth0 gives the index (from 0) of an element in a list
% element V is at the place Id1 in L
nth0(Id1, L, V),
% element V is at the place Id2 in L
nth0(Id2, L, V),
% Id1 is different from Id2
% It is more usefull to say that Id1 < Id2
% Thanks **false** for the improvement
Id1 < Id2.
Another way to do this is to say : I remove the element of the list (this is done in SWI-Prolog by select/3) and I check if it's in the rest of the list :
duplicate(L, V) :-
select(V, L, L1),
member(V, L1).
Pure and simple! Use meta-predicate tcount/3 with reified term equality (=)/3 like so:
?- tcount(=(X), [1,2,3,4,1], 2).
X = 1 ; % succeeds, but leaves choicepoint
false.
?- tcount(=(1), [1,2,3,4,1], 2).
true. % succeeds deterministically
?- tcount(=(X), [b,c,d,a,b,a,c], 2).
X = b ;
X = c ;
X = a ;
false.
?- tcount(=(a), [b,c,d,a,b,a,c], 2).
true. % succeeds deterministically
Last, let's run the following quite general query:
?- tcount(=(a), Ls, 2).
Ls = [a,a] ;
Ls = [a,a,_X], dif(_X,a) ;
Ls = [a,a,_X,_Y], dif(_X,a), dif(_Y,a) ;
Ls = [a,a,_X,_Y,_Z], dif(_X,a), dif(_Y,a), dif(_Z,a) ...
The solution by #false is as clean as it will get. Here is a more verbose solution that states the problem in simpler terms. One thing to remember is that a "duplicated" element might mean that an element occurs exactly twice -- this is how this predicate interprets it -- or it might mean that an element occurs more than once -- this is what you probably mean (so the name duplicate is in fact misleading)
%% duplicate(List, Element) is true for every matching pair of _Element_ in _List_
duplicate([First|Rest], Element) :-
duplicate_1(Rest, First, Element).
% First occurrence
duplicate_1([This|Rest], X, X) :- % first occurrence
duplicate_2(Rest, This, X).
duplicate_1([This|Rest], _, X) :- % look further for first occurrence
duplicate_1(Rest, This, X).
% Second occurrence
duplicate_2(_, X, X). % second occurrence
duplicate_2([This|Rest], _, X) :- % look further for second occurrence
duplicate_2(Rest, This, X).
This can now be used in all directions:
?- duplicate([b,c,d,a,b,a,c], X).
X = b ;
X = c ;
X = a ;
false.
?- duplicate([b,c,d,a,b,a,c], a).
true ;
false.
?- duplicate(L, a).
L = [a, a|_G274] ;
L = [a, _G273, a|_G277] ;
L = [a, _G273, _G276, a|_G280] .
You will have to use cuts, or dif/2, or once/1 to get rid of the multiple answers, if they are a problem. How exactly depends on how you want to use the predicate.
for the first part of your problem I have found a simple solution:
duplicated([H|T], Item) :- H == Item, second_stage(T, Item). %first occurence found
duplicated([H|T], Item) :- duplicated(T, Item).
second_stage([H|T], Item) :- H == Item. %second occurence found -> match!
second_stage([H|T], Item) :- second_stage(T, Item).
This will give true f.e. with duplicated([1,2,3,1,5], 1).
For the second part (query with Variable) I will try to find a way...but I dont
know if this is possible in Prolog.
:)

Add two more occurrences using prolog

I have a list [a, b, a, a, a, c, c]
and I need to add two more occurrences of each element.
The end result should look like this:
[a, a, a, b, b, b, a, a, a, a, a, c, c, c, c]
If I have an item on the list that is the same as the next item, then it keeps going until there is a new item, when it finds the new item, it adds two occurrences of the previous item then moves on.
This is my code so far, but I can't figure out how to add two...
dbl([], []).
dbl([X], [X,X]).
dbl([H|T], [H,H|T], [H,H|R]) :- dbl(T, R).
Your code looks a bit strange because the last rule takes three parameters. You only call the binary version, so no recursion will ever try to derive it.
You already had a good idea to look at the parts of the list, where elements change. So there are 4 cases:
1) Your list is empty.
2) You have exactly one element.
3) Your list starts with two equal elements.
4) Your list starts with two different elements.
Case 1 is not specified, so you might need to find a sensible choice for that. Case 2 is somehow similar to case 4, since the end of the list can be seen as a change in elements, where you need to append two copies, but then you are done. Case 3 is quite simple, we can just keep the element and recurse on the rest. Case 4 is where you need to insert the two copies again.
This means your code will look something like this:
% Case 1
dbl([],[]).
% Case 2
dbl([X],[X,X,X]).
% Case 3
dbl([X,X|Xs], [X|Ys]) :-
% [...] recursion skipping the leading X
% Case 4
dbl([X,Y|Xs], [X,X,X|Ys]) :-
dif(X,Y),
% [...] we inserted the copies, so recursion on [Y|Xs] and Ys
Case 3 should be easy to finish, we just drop the first X from both lists and recurse on dbl([X|Xs],Ys). Note that we implicitly made the first two elements equal (i.e. we unified them) by writing the same variable twice.
If you look at the head of case 4, you can directly imitate the pattern you described: supposed the list starts with X, then Y and they are different (dif(X,Y)), the X is repeated 3 times instead of just copied and we then continue with the recursion on the rest starting with Y: dbl([Y|Xs],Ys).
So let's try out the predicate:
?- dbl([a,b,a,a,a,c,c],[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]).
true ;
false.
Our test case is accepted (true) and we don't find more than one solution (false).
Let's see if we find a wrong solution:
?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), dbl([a,b,a,a,a,c,c],Xs).
false.
No, that's also good. What happens, if we have variables in our list?
?- dbl([a,X,a],Ys).
X = a,
Ys = [a, a, a, a, a] ;
Ys = [a, a, a, X, X, X, a, a, a],
dif(X, a),
dif(X, a) ;
false.
Either X = a, then Ys is single run of 5 as; or X is not equal to a, then we need to append the copies in all three runs. Looks also fine. (*)
Now lets see, what happens if we only specify the solution:
?- dbl(X,[a,a,a,b,b]).
false.
Right, a list with a run of only two bs can not be a result of our specification. So lets try to add one:
?- dbl(X,[a,a,a,b,b,b]).
X = [a, b] ;
false.
Hooray, it worked! So lets as a last test look what happens, if we just call our predicate with two variables:
?- dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G15],
Ys = [_G15, _G15, _G15] ;
Xs = [_G15, _G15],
Ys = [_G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15, _G15] ;
[...]
It seems we get the correct answers, but we see only cases for a single run. This is a result of prolog's search strategy(which i will not explain in here). But if we look at shorter lists before we generate longer ones, we can see all the solutions:
?- length(Xs,_), dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G16],
Ys = [_G16, _G16, _G16] ;
Xs = [_G16, _G16],
Ys = [_G16, _G16, _G16, _G16] ;
Xs = [_G86, _G89],
Ys = [_G86, _G86, _G86, _G89, _G89, _G89],
dif(_G86, _G89) ;
Xs = [_G16, _G16, _G16],
Ys = [_G16, _G16, _G16, _G16, _G16] ;
Xs = [_G188, _G188, _G194],
Ys = [_G188, _G188, _G188, _G188, _G194, _G194, _G194],
dif(_G188, _G194) ;
[...]
So it seems we have a working predicate (**), supposed you filled in the missing goals from the text :)
(*) A remark here: this case only works because we are using dif. The first predicates with equality, one usually encounters are =, == and their respective negations \= and \==. The = stands for unifyability (substituting variables in the arguments s.t. they become equal) and the == stands for syntactic equality (terms being exactly equal). E.g.:
?- f(X) = f(a).
X = a.
?- f(X) \= f(a).
false.
?- f(X) == f(a).
false.
?- f(X) \== f(a).
true.
This means, we can make f(X) equal to f(a), if we substitute X by a. This means if we ask if they can not be made equal (\=), we get the answer false. On the other hand, the two terms are not equal, so == returns false, and its negation \== answers true.
What this also means is that X \== Y is always true, so we can not use \== in our code. In contrast to that, dif waits until it can decide wether its arguments are equal or not. If this is still undecided after finding an answer, the "dif(X,a)" statements are printed.
(**) One last remark here: There is also a solution with the if-then-else construct (test -> goals_if_true; goals_if_false, which merges cases 3 and 4. Since i prefer this solution, you might need to look into the other version yourself.
TL;DR:
From a declarative point of view, the code sketched by #lambda.xy.x is perfect.
Its determinacy can be improved without sacrificing logical-purity.
Code variant #0: #lambda.xy.x's code
Here's the code we want to improve:
dbl0([], []).
dbl0([X], [X,X,X]).
dbl0([X,X|Xs], [X|Ys]) :-
dbl0([X|Xs], Ys).
dbl0([X,Y|Xs], [X,X,X|Ys]) :-
dif(X, Y),
dbl0([Y|Xs], Ys).
Consider the following query and the answer SWI-Prolog gives us:
?- dbl0([a],Xs).
Xs = [a,a,a] ;
false.
With ; false the SWI prolog-toplevel
indicates a choicepoint was left when proving the goal.
For the first answer, Prolog did not search the entire proof tree.
Instead, it replied "here's an answer, there may be more".
Then, when asked for more solutions, Prolog traversed the remaining branches of the proof tree but finds no more answers.
In other words: Prolog needs to think twice to prove something we knew all along!
So, how can we give determinacy hints to Prolog?
By utilizing:
control constructs !/0 and / or (->)/2 (potentially impure)
first argument indexing on the principal functor (never impure)
The code presented in the earlier answer by #CapelliC—which is based on !/0, (->)/2, and the meta-logical predicate (\=)/2—runs well if all arguments are sufficiently instantiated. If not, erratic answers may result—as #lambda.xy.x's comment shows.
Code variant #1: indexing
Indexing can improve determinacy without ever rendering the code non-monotonic. While different Prolog processors have distinct advanced indexing capabilities, the "first-argument principal-functor" indexing variant is widely available.
Principal? This is why executing the goal dbl0([a],Xs) leaves a choicepoint behind: Yes, the goal only matches one clause—dbl0([X],[X,X,X]).—but looking no deeper than the principal functor Prolog assumes that any of the last three clauses could eventually get used. Of course, we know better...
To tell Prolog we utilize principal-functor first-argument indexing:
dbl1([], []).
dbl1([E|Es], Xs) :-
dbl1_(Es, Xs, E).
dbl1_([], [E,E,E], E).
dbl1_([E|Es], [E|Xs], E) :-
dbl1_(Es, Xs, E).
dbl1_([E|Es], [E0,E0,E0|Xs], E0) :-
dif(E0, E),
dbl1_(Es, Xs, E).
Better? Somewhat, but determinacy could be better still...
Code variant #2: indexing on reified term equality
To make Prolog see that the two recursive clauses of dbl1_/3 are mutually exclusive (in certain cases), we reify the truth value of
term equality and then index on that value:
This is where reified term equality (=)/3 comes into play:
dbl2([], []).
dbl2([E|Es], Xs) :-
dbl2_(Es, Xs, E).
dbl2_([], [E,E,E], E).
dbl2_([E|Es], Xs, E0) :-
=(E0, E, T),
t_dbl2_(T, Xs, E0, E, Es).
t_dbl2_(true, [E|Xs], _, E, Es) :-
dbl2_(Es, Xs, E).
t_dbl2_(false, [E0,E0,E0|Xs], E0, E, Es) :-
dbl2_(Es, Xs, E).
Sample queries using SWI-Prolog:
?- dbl0([a],Xs).
Xs = [a, a, a] ;
false.
?- dbl1([a],Xs).
Xs = [a, a, a].
?- dbl2([a],Xs).
Xs = [a, a, a].
?- dbl0([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b] ;
false.
?- dbl1([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b] ;
false.
?- dbl2([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b].
To make above code more compact, use control construct if_/3 .
I was just about to throw this version with if_/3 and (=)/3 in the hat when I saw #repeat already suggested it. So this is essentially the more compact version as outlined by #repeat:
list_dbl([],[]).
list_dbl([X],[X,X,X]).
list_dbl([A,B|Xs],DBL) :-
if_(A=B,DBL=[A,B|Ys],DBL=[A,A,A,B|Ys]),
list_dbl([B|Xs],[B|Ys]).
It yields the same results as dbl2/2 by #repeat:
?- list_dbl([a],DBL).
DBL = [a,a,a]
?- list_dbl([a,b,b],DBL).
DBL = [a,a,a,b,b,b,b]
The example query by the OP works as expected:
?- list_dbl([a,b,a,a,a,c,c],DBL).
DBL = [a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]
Plus here are some of the example queries provided by #lambda.xy.x. They yield the same results as #repeat's dbl/2 and #lambda.xy.x's dbl/2:
?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), list_dbl([a,b,a,a,a,c,c],Xs).
no
?- list_dbl(X,[a,a,a,b,b]).
no
?- list_dbl(L,[a,a,a,b,b,b]).
L = [a,b] ? ;
no
?- list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ? ;
...
?- list_dbl([a,X,a],DBL).
DBL = [a,a,a,a,a],
X = a ? ;
DBL = [a,a,a,X,X,X,a,a,a],
dif(X,a),
dif(a,X)
?- length(L,_), list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_B,_B,_B],
L = [_A,_B],
dif(_A,_B) ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ?
dbl([X,Y|T], [X,X,X|R]) :- X \= Y, !, dbl([Y|T], R).
dbl([H|T], R) :-
T = []
-> R = [H,H,H]
; R = [H|Q], dbl(T, Q).
The first clause handles the basic requirement, adding two elements on sequence change.
The second one handles list termination as a sequence change, otherwise, does a plain copy.

Even sized list in Prolog

I've been trying to write a predicate which would evaluate the size of a list to be even or not and this has to be done without computing the length of the list or any arithmetic operations. It's supposedly easier than computing the length but I'm having trouble thinking of how to do it without that. I'm guessing a sort of recursive technique but if anyone is able to help it would be great.
Yes, you want recursion. The base cases would be the smallest odd/even lists you can have, and then all you need is to figure out how to construct the recursive call so that it will boil down to the base case. You could start out by imagining a list of length 3 that's supposed to return true for "oddList". If it's not the base case, what's the next logical step? How does an odd list differ from an even one?
Preserve logical-purity! Simply proceed like this:
evenlength([]). % smallest list with even length is [] (length=0)
evenlength([_|Xs]) :-
oddlength(Xs).
oddlength([_|Xs]) :- % smallest list with odd length is [_] (length=1)
evenlength(Xs).
Some simple ground queries for evenlength/1 and oddlength/1:
?- evenlength([]).
true.
?- oddlength([]).
false.
?- evenlength([1]).
false.
?- oddlength([1]).
true.
?- evenlength([1,2]).
true.
?- oddlength([1,2]).
false.
?- evenlength([1,2,3]).
false.
?- oddlength([1,2,3]).
true.
Note that these predicates can not only test candidate lists, but also generate them:
?- evenlength(Xs).
Xs = []
; Xs = [_A,_B]
; Xs = [_A,_B,_C,_D]
; Xs = [_A,_B,_C,_D,_E,_F]
...
?- oddlength(Xs).
Xs = [_A]
; Xs = [_A,_B,_C]
; Xs = [_A,_B,_C,_D,_E]
; Xs = [_A,_B,_C,_D,_E,_F,_G]
...
Using meta-predicate foldl/4 and Prolog lambdas all we need to do is:
evenlength(Xs) :-
foldl(\_^E^O^(O is \E),Xs,1,1). % each item in `Xs` flips the "evenness flag"
Sample uses:
?- evenlength([]).
true.
?- evenlength([_]).
false.
?- evenlength([_,_]).
true.
?- evenlength([_,_,_]).
false.
?- evenlength([_,_,_,_]).
true.
Let's not forget about the most general query!
?- evenlength(Xs).
Xs = []
; Xs = [_A,_B]
; Xs = [_A,_B,_C,_D]
; Xs = [_A,_B,_C,_D,_E,_F]
...
I know it is too late to answer your question, but hopefully this will help:
To find list has odd length:
oddlength([_]).
oddlength([_,_|R]) :- oddlength(R),!.
To find list has even length:
evenlength([]).
evenlength([_,_|R]) :- evenlength(R),!.