Prolog - Count the Number of Repetitions in a List - list

I'm writing a program in Prolog that counts the number of uninterrupted occurrences of the first value in a list.
So given, repetitions(N, [a,a,a,a,a,b,c,a]), the program would return N = 5.
This is what my code looks like so far:
repetitions(A,[]).
repetitions(A,[A|T]) :- repetitions(A,[_|T]), A is 1+A.
repetitions(A,[_|T]) :- repetitions(A,[A|T]).

Here is a relational version:
repetitions(N, [First|Rest]) :-
phrase(repetitions_(First, 1, N), Rest).
repetitions_(_, N, N) --> [].
repetitions_(First, N0, N) --> [First],
{ N1 #= N0 + 1 },
repetitions_(First, N1, N).
repetitions_(First, N, N) --> [Other], { dif(First, Other) }, ... .
... --> [] | [_], ... .
The test case works as required:
?- repetitions(N, [a,a,a,a,a,b,c,a]).
N = 5 ;
false.
And moreover, we can also use this in other directions.
For example, what about a list with 3 element in general:
?- Ls = [A,B,C], repetitions(N, Ls).
Ls = [C, C, C],
A = B, B = C,
N = 3 ;
Ls = [B, B, C],
A = B,
N = 2,
dif(B, C) ;
Ls = [A, B, C],
N = 1,
dif(A, B) ;
false.
And what about all possible answers, fairly enumerated by iterative deepening:
?- length(Ls, _), repetitions(N, Ls).
Ls = [_8248],
N = 1 ;
Ls = [_8248, _8248],
N = 2 ;
Ls = [_8734, _8740],
N = 1,
dif(_8734, _8740) ;
Ls = [_8248, _8248, _8248],
N = 3 ;
Ls = [_8740, _8740, _8752],
N = 2,
dif(_8740, _8752) ;
etc.
It is a major attraction of logic programs that they can often be used in several directions.
See dcg, prolog-dif and clpfd for more information about the mechanisms I used to achieve this generality.
We can also use this to answer the following question
What does a list look like such that there are 3 repetitions of its first element?
Example:
?- repetitions(3, Ls).
Ls = [_2040, _2040, _2040] ;
Ls = [_2514, _2514, _2514, _2532],
dif(_2514, _2532) ;
Ls = [_2526, _2526, _2526, _2544, _2550],
dif(_2526, _2544) ;
Ls = [_2538, _2538, _2538, _2556, _2562, _2568],
dif(_2538, _2556) .
This requires only that a single further constraint be added to the solution above. I leave this as an easy exercise.

Here is a DCG-based solution somewhat a variation to #mat's:
repetitions_II(N, [X|Cs]) :-
phrase( ( reps(X, N), no(X) ), [X|Cs]).
no(X) -->
( [] | [Y], {dif(X,Y)}, ... ).
reps(_X, 0) -->
[].
reps(X, N0) -->
[X],
{ N0 #> 0, N1 #= N0-1 },
reps(X, N1).
Two notable differences:
1mo) There is no use of a difference for maintaining the counter. Thus, constraints on the number can help to improve termination. A perfect clpfd-implementation would (or rather should) implement this with similar efficiency to a difference.
2do) The end no//1 essentially encodes in a pure manner \+[X].
The downside of this solution is that it still produces leftover choicepoints. To get rid of these, some more manual coding is necessary:
:- use_module(library(reif)).
repetitions_III(N, [X|Xs]) :-
reps([X|Xs], X, N).
reps([], _, 0).
reps([X|Xs], C, N0) :-
N0 #>= 0,
if_(X = C, ( N1 #= N0-1, reps(Xs, C, N1) ), N0 = 0 ).

Another approach close to what you've done so far, using CLPFD:
:- use_module(library(clpfd)).
repetitions(N,[H|T]):-repetitions(N,[H|T],H).
repetitions(0,[],_).
repetitions(0,[H|_],H1):-dif(H,H1).
repetitions(N,[H|T],H):-repetitions(N1 ,T, H), N #= N1+1.
Examples:
?- repetitions(A,[a,a,a,a,a,b,c,a]).
A = 5 ;
false.
?- repetitions(2,[a,Y]).
Y = a.
?- repetitions(N,[a,a|_]).
N = 2 ;
N = 2 ;
N = 3 ;
N = 3 ;
N = 4 ;
N = 4 ;
N = 5 ;
N = 5 ;
N = 6 ;
N = 6 ....and goes on

a compact definition, courtesy libraries apply and yall
?- [user].
repetitions(A,[H|T]) :- foldl([E,(C0,H0),(C1,H1)]>>(E==H0 -> succ(C0,C1), H1=H0 ; C0=C1, H1=_), T, (1,H), (A,_)).
|: true.
?- repetitions(A,[a,a,a,a,a,b,c,a]).
A = 5.

Related

A length/2 predicate that works with constraints [duplicate]

Here is the problem:
$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.6-5-g5aeabd5)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- use_module(library(clpfd)).
true.
?- N in 1..3, length(L, N).
N = 1,
L = [_G1580] ;
N = 2,
L = [_G1580, _G1583] ;
N = 3,
L = [_G1580, _G1583, _G1586] ;
ERROR: Out of global stack % after a while
(I can switch the order of the subqueries, the result is the same).
I guess I need to label N before I can use it, but I wonder what the problem is? I have not managed to choke up length/2 before.
What's probably more useful than a slightly less nondeterministic length/2 is a proper list-length constraint. You can find an ECLiPSe implementation of it here, called len/2. With this you get the following behaviour:
?- N :: 1..3, len(Xs, N).
N = N{1 .. 3}
Xs = [_431|_482] % note it must contain at least one element!
There is 1 delayed goal.
Yes (0.00s cpu)
You can then enumerate the valid lists either by enumerating N:
?- N :: 1..3, len(Xs, N), indomain(N).
N = 1
Xs = [_478]
Yes (0.00s cpu, solution 1, maybe more)
N = 2
Xs = [_478, _557]
Yes (0.02s cpu, solution 2, maybe more)
N = 3
Xs = [_478, _557, _561]
Yes (0.02s cpu, solution 3)
or by generating lists with good old standard length/2:
?- N :: 1..3, len(Xs, N), length(Xs, _).
N = 1
Xs = [_488]
Yes (0.00s cpu, solution 1, maybe more)
N = 2
Xs = [_488, _555]
Yes (0.02s cpu, solution 2, maybe more)
N = 3
Xs = [_488, _555, _636]
Yes (0.02s cpu, solution 3)
Let's start with the most obvious one. If you switch the goals, you have:
?- length(L, N), N in 1..3.
which has the same termination properties as:
?- length(L, N), false, N in 1..3.
So obviously, this must not terminate with Prolog's execution mechanism.
However, if you put N in 1..3 in front, this might affect termination. To do so, it must be possible with finite means to prove that there is no N from 4 on. How can you prove this in a system without constraints - that is, only with syntactic unification present? Well, you can't. And length/2 is commonly defined just without constraints present.
With library(clpfd) things are trivial, for N #>= 4, N in 1..3 simply fails1. Note also that library(clpfd) does not collaborate much with library(clpq) which might be an interesting candidate, too.
As a consequence you would need to define your own length — for each constraint package you are interested in. That's a bit of a pity, but currently there is no generic way to do so in sight. ((That is, if you are interested and think a bit about it, you might come up with a nice API that every constraint system should adhere to. Alas, this will take some more decades, I suspect. Currently, there is much too much divergence.))
So here is a first naive way for fd_length/2:
fd_length([], N) :-
N #= 0.
fd_length([_|L], N0) :-
N0 #>= 1,
N1 #= N0-1,
fd_length(L, N1).
OK, this could be optimized to avoid the superfluous choicepoint. But there is a more fundamental problem: If you are determining the length of a list of length N, this will create N constraint variables! But we do need only one.
fd_length(L, N) :-
N #>= 0,
fd_length(L, N, 0).
fd_length([], N, N0) :-
N #= N0.
fd_length([_|L], N, N0) :-
N1 is N0+1,
N #>= N1,
fd_length(L, N, N1).
Again, this is not perfect for so many reasons: It could use Brent's algorithm like current systems do ; and combine it with all the fd properties. Also, arithmetic expressions are probably not a good idea to permit ; but I would have to wait for (#)/1 in SWI...
1: Strictly speaking, this "simply fails" only for SICStus, SWI, and YAP. For in those systems, there is no accidental failure due to exhaustion of the current representation. That is, their failure can always be taken as an honest no.
How about the following baroque work-around based on clpfd and meta-predicate tcount/3?
:- use_module([library(clpfd), library(lambda)]).
list_FDlen(Xs, N) :-
tcount(\_^ =(true), Xs, N).
Let's query!
?- N in 1..3, list_FDlen(Xs, N).
N = 1, Xs = [_A]
; N = 2, Xs = [_A,_B]
; N = 3, Xs = [_A,_B,_C]
; false. % terminates universally
?- N in inf..2, list_FDlen(Xs, N).
N = 0, Xs = []
; N = 1, Xs = [_A]
; N = 2, Xs = [_A,_B]
; false. % terminates universally, too
What about this particular query?
?- N in 2..sup, list_FDlen(Xs, N).
N = 2, Xs = [_A,_B]
; N = 3, Xs = [_A,_B,_C]
; N = 4, Xs = [_A,_B,_C,_D]
... % does not terminate (as expected)
We present a clpfd-ish variant of
length/2 that's tailored to #mat's clpfd implementation.
:- use_module(library(clpfd)).
:- use_module(library(dialect/sicstus)).
:- multifile clpfd:run_propagator/2.
The "exported" predicate lazy_len/2 is defined like this:
lazy_len(Es, N) :-
N in 0..sup, % lengths are always non-negative integers
lazylist_acc_len(Es, 0, N),
create_mutable(Es+0, State),
clpfd:make_propagator(list_FD_size(State,N), Propagator),
clpfd:init_propagator(N, Propagator),
clpfd:trigger_once(Propagator).
The global constraint handler list_FD_size/3 incrementally modifies its internal state as constraint propagation occurs. All modifications are trailed and are un-done upon backtracking.
clpfd:run_propagator(list_FD_size(State,N), _MState) :-
get_mutable(Es0+Min0, State),
fd_inf(N, Min),
Diff is Min - Min0,
length(Delta, Diff),
append(Delta, Es, Es0),
( integer(N)
-> Es = []
; Delta = []
-> true % unchanged
; update_mutable(Es+Min, State)
).
lazy_len/2 tackles the problem from two sides; the clpfd constraint part of it was shown above. The tree side uses prolog-coroutining to walk down the list as far as the partial instantiation allows1:
lazylist_acc_len(_, _, N) :-
integer(N),
!.
lazylist_acc_len(Es, N0, N) :-
var(Es),
!,
when((nonvar(N);nonvar(Es)), lazylist_acc_len(Es,N0,N)).
lazylist_acc_len([], N, N).
lazylist_acc_len([_|Es], N0, N) :-
N1 is N0+1,
N in N1..sup,
lazylist_acc_len(Es, N1, N).
Sample queries:
?- lazy_len(Xs, N).
when((nonvar(N);nonvar(Xs)), lazylist_acc_len(Xs,0,N)),
N in 0..sup,
list_FD_size(Xs+0, N).
?- lazy_len(Xs, 3).
Xs = [_A,_B,_C].
?- lazy_len([_,_], L).
L = 2.
?- lazy_len(Xs, L), L #> 0.
Xs = [_A|_B],
when((nonvar(L);nonvar(_B)), lazylist_acc_len(_B,1,L)),
L in 1..sup,
list_FD_size(_B+1, L).
?- lazy_len(Xs, L), L #> 2.
Xs = [_A,_B,_C|_D],
when((nonvar(L);nonvar(_D)), lazylist_acc_len(_D,3,L)),
L in 3..sup,
list_FD_size(_D+3, L).
?- lazy_len(Xs, L), L #> 0, L #> 2.
Xs = [_A,_B,_C|_D],
when((nonvar(L);nonvar(_D)), lazylist_acc_len(_D,3,L)),
L in 3..sup,
list_FD_size(_D+3, L).
And, at long last, one more query... well, actually two more: one going up—the other going down.
?- L in 1..4, lazy_len(Xs, L), labeling([up], [L]).
L = 1, Xs = [_A]
; L = 2, Xs = [_A,_B]
; L = 3, Xs = [_A,_B,_C]
; L = 4, Xs = [_A,_B,_C,_D].
?- L in 1..4, lazy_len(Xs, L), labeling([down], [L]).
L = 4, Xs = [_A,_B,_C,_D]
; L = 3, Xs = [_A,_B,_C]
; L = 2, Xs = [_A,_B]
; L = 1, Xs = [_A].
Footnote 1:
Here, we focus on preserving determinism (avoid the creation of choice-points) by using delayed goals.

Numbers in a list smaller than a given number

xMenores(_,[],[]).
xMenores(X,[H|T],[R|Z]) :-
xMenores(X,T,Z),
X > H,
R is H.
xMenores takes three parameters:
The first one is a number.
The second is a list of numbers.
The third is a list and is the variable that will contain the result.
The objective of the rule xMenores is obtain a list with the numbers of the list (Second parameter) that are smaller than the value on the first parameter. For example:
?- xMenores(3,[1,2,3],X).
X = [1,2]. % expected result
The problem is that xMenores returns false when X > H is false and my programming skills are almost null at prolog. So:
?- xMenores(4,[1,2,3],X).
X = [1,2,3]. % Perfect.
?- xMenores(2,[1,2,3],X).
false. % Wrong! "X = [1]" would be perfect.
I consider X > H, R is H. because I need that whenever X is bigger than H, R takes the value of H. But I don't know a control structure like an if or something in Prolog to handle this.
Please, any solution? Thanks.
Using ( if -> then ; else )
The control structure you might be looking for is ( if -> then ; else ).
Warning: you should probably swap the order of the first two arguments:
lessthan_if([], _, []).
lessthan_if([X|Xs], Y, Zs) :-
( X < Y
-> Zs = [X|Zs1]
; Zs = Zs1
),
lessthan_if(Xs, Y, Zs1).
However, if you are writing real code, you should almost certainly go with one of the predicates in library(apply), for example include/3, as suggested by #CapelliC:
?- include(>(3), [1,2,3], R).
R = [1, 2].
?- include(>(4), [1,2,3], R).
R = [1, 2, 3].
?- include(<(2), [1,2,3], R).
R = [3].
See the implementation of include/3 if you want to know how this kind of problems are solved. You will notice that lessthan/3 above is nothing but a specialization of the more general include/3 in library(apply): include/3 will reorder the arguments and use the ( if -> then ; else ).
"Declarative" solution
Alternatively, a less "procedural" and more "declarative" predicate:
lessthan_decl([], _, []).
lessthan_decl([X|Xs], Y, [X|Zs]) :- X < Y,
lessthan_decl(Xs, Y, Zs).
lessthan_decl([X|Xs], Y, Zs) :- X >= Y,
lessthan_decl(Xs, Y, Zs).
(lessthan_if/3 and lessthan_decl/3 are nearly identical to the solutions by Nicholas Carey, except for the order of arguments.)
On the downside, lessthan_decl/3 leaves behind choice points. However, it is a good starting point for a general, readable solution. We need two code transformations:
Replace the arithmetic comparisons < and >= with CLP(FD) constraints: #< and #>=;
Use a DCG rule to get rid of arguments in the definition.
You will arrive at the solution by lurker.
A different approach
The most general comparison predicate in Prolog is compare/3. A common pattern using it is to explicitly enumerate the three possible values for Order:
lessthan_compare([], _, []).
lessthan_compare([H|T], X, R) :-
compare(Order, H, X),
lessthan_compare_1(Order, H, T, X, R).
lessthan_compare_1(<, H, T, X, [H|R]) :-
lessthan_compare(T, X, R).
lessthan_compare_1(=, _, T, X, R) :-
lessthan_compare(T, X, R).
lessthan_compare_1(>, _, T, X, R) :-
lessthan_compare(T, X, R).
(Compared to any of the other solutions, this one would work with any terms, not just integers or arithmetic expressions.)
Replacing compare/3 with zcompare/3:
:- use_module(library(clpfd)).
lessthan_clpfd([], _, []).
lessthan_clpfd([H|T], X, R) :-
zcompare(ZOrder, H, X),
lessthan_clpfd_1(ZOrder, H, T, X, R).
lessthan_clpfd_1(<, H, T, X, [H|R]) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(=, _, T, X, R) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(>, _, T, X, R) :-
lessthan_clpfd(T, X, R).
This is definitely more code than any of the other solutions, but it does not leave behind unnecessary choice points:
?- lessthan_clpfd(3, [1,3,2], Xs).
Xs = [1, 2]. % no dangling choice points!
In the other cases, it behaves just as the DCG solution by lurker:
?- lessthan_clpfd(X, [1,3,2], Xs).
Xs = [1, 3, 2],
X in 4..sup ;
X = 3,
Xs = [1, 2] ;
X = 2,
Xs = [1] ;
X = 1,
Xs = [] .
?- lessthan_clpfd(X, [1,3,2], Xs), X = 3. %
X = 3,
Xs = [1, 2] ; % no error!
false.
?- lessthan_clpfd([1,3,2], X, R), R = [1, 2].
X = 3,
R = [1, 2] ;
false.
Unless you need such a general approach, include(>(X), List, Result) is good enough.
This can also be done using a DCG:
less_than([], _) --> [].
less_than([H|T], N) --> [H], { H #< N }, less_than(T, N).
less_than(L, N) --> [H], { H #>= N }, less_than(L, N).
| ?- phrase(less_than(R, 4), [1,2,3,4,5,6]).
R = [1,2,3] ? ;
You can write your predicate as:
xMenores(N, NumberList, Result) :- phrase(less_than(Result, N), NumberList).
You could write it as a one-liner using findall\3:
filter( N , Xs , Zs ) :- findall( X, ( member(X,Xs), X < N ) , Zs ) .
However, I suspect that the point of the exercise is to learn about recursion, so something like this would work:
filter( _ , [] , [] ) .
filter( N , [X|Xs] , [X|Zs] ) :- X < N , filter(N,Xs,Zs) .
filter( N , [X|Xs] , Zs ) :- X >= N , filter(N,Xs,Zs) .
It does, however, unpack the list twice on backtracking. An optimization here would be to combine the 2nd and 3rd clauses by introducing a soft cut like so:
filter( _ , [] , [] ) .
filter( N , [X|Xs] , [X|Zs] ) :-
( X < N -> Zs = [X|Z1] ; Zs = Z1 ) ,
filter(N,Xs,Zs)
.
(This is more like a comment than an answer, but too long for a comment.)
Some previous answers and comments have suggested using "if-then-else" (->)/2 or using library(apply) meta-predicate include/3. Both methods work alright, as long as only plain-old Prolog arithmetics—is/2, (>)/2, and the like—are used ...
?- X = 3, include(>(X),[1,3,2,5,4],Xs).
X = 3, Xs = [1,2].
?- include(>(X),[1,3,2,5,4],Xs), X = 3.
ERROR: >/2: Arguments are not sufficiently instantiated
% This is OK. When instantiation is insufficient, an exception is raised.
..., but when doing the seemingly benign switch from (>)/2 to (#>)/2, we lose soundness!
?- X = 3, include(#>(X),[1,3,2,5,4],Xs).
X = 3, Xs = [1,2].
?- include(#>(X),[1,3,2,5,4],Xs), X = 3.
false.
% This is BAD! Expected success with answer substitutions `X = 3, Xs = [1,2]`.
No new code is presented in this answer.
In the following we take a detailed look at different revisions of this answer by #lurker.
Revision #1, renamed to less_than_ver1//2. By using dcg and clpfd, the code is both very readable and versatile:
less_than_ver1(_, []) --> [].
less_than_ver1(N, [H|T]) --> [H], { H #< N }, less_than_ver1(N, T).
less_than_ver1(N, L) --> [H], { H #>= N }, less_than_ver1(N, L).
Let's query!
?- phrase(less_than_ver1(N,Zs),[1,2,3,4,5]).
N in 6..sup, Zs = [1,2,3,4,5]
; N = 5 , Zs = [1,2,3,4]
; N = 4 , Zs = [1,2,3]
; N = 3 , Zs = [1,2]
; N = 2 , Zs = [1]
; N in inf..1, Zs = []
; false.
?- N = 3, phrase(less_than_ver1(N,Zs),[1,2,3,4,5]).
N = 3, Zs = [1,2] % succeeds, but leaves useless choicepoint
; false.
?- phrase(less_than_ver1(N,Zs),[1,2,3,4,5]), N = 3.
N = 3, Zs = [1,2]
; false.
As a small imperfection, less_than_ver1//2 leaves some useless choicepoints.
Let's see how things went with the newer revision...
Revision #3, renamed to less_than_ver3//2:
less_than_ver3([],_) --> [].
less_than_ver3(L,N) --> [X], { X #< N -> L=[X|T] ; L=T }, less_than_ver3(L,N).
This code uses the if-then-else ((->)/2 + (;)/2) in order to improve determinism.
Let's simply re-run the above queries!
?- phrase(less_than_ver3(Zs,N),[1,2,3,4,5]).
N in 6..sup, Zs = [1,2,3,4,5]
; false. % all other solutions are missing!
?- N = 3, phrase(less_than_ver3(Zs,N),[1,2,3,4,5]).
N = 3, Zs = [1,2] % works as before, but no better.
; false. % we still got the useless choicepoint
?- phrase(less_than_ver3(Zs,N),[1,2,3,4,5]), N = 3.
false. % no solution!
% we got one with revision #1!
Surprise! Two cases that worked before are now (somewhat) broken, and the determinism in the ground case is no better... Why?
The vanilla if-then-else often cuts too much too soon, which is particularly problematic with code which uses coroutining and/or constraints.
Note that (*->)/2 (a.k.a. "soft-cut" or if/3), fares only a bit better, not a lot!
As if_/3 never ever cuts more (often than) the vanilla if-then-else (->)/2, it cannot be used in above code to improve determinism.
If you want to use if_/3 in combination with constraints, take a step back and write code that is non-dcg as the first shot.
If you're lazy like me, consider using a meta-predicate like tfilter/3 and (#>)/3.
This answer by #Boris presented a logically pure solution which utilizes clpfd:zcompare/3 to help improve determinism in certain (ground) cases.
In this answer we will explore different ways of coding logically pure Prolog while trying to avoid the creation of useless choicepoints.
Let's get started with zcompare/3 and (#<)/3!
zcompare/3 implements three-way comparison of finite domain variables and reifies the trichotomy into one of <, =, or >.
As the inclusion criterion used by the OP was a arithmetic less-than test, we propose using
(#<)/3 for reifying the dichotomy into one of true or false.
Consider the answers of the following queries:
?- zcompare(Ord,1,5), #<(1,5,B).
Ord = (<), B = true.
?- zcompare(Ord,5,5), #<(5,5,B).
Ord = (=), B = false.
?- zcompare(Ord,9,5), #<(9,5,B).
Ord = (>), B = false.
Note that for all items to be selected both Ord = (<) and B = true holds.
Here's a side-by-side comparison of three non-dcg solutions based on clpfd:
The left one uses zcompare/3 and first-argument indexing on the three cases <, =, and >.
The middle one uses (#<)/3 and first-argument indexing on the two cases true and false.
The right one uses (#<)/3 in combination with if_/3.
Note that we do not need to define auxiliary predicates in the right column!
less_than([],[],_). % less_than([],[],_). % less_than([],[],_).
less_than([Z|Zs],Ls,X) :- % less_than([Z|Zs],Ls,X) :- % less_than([Z|Zs],Ls,X) :-
zcompare(Ord,Z,X), % #<(Z,X,B), % if_(Z #< X,
ord_lt_(Ord,Z,Ls,Rs), % incl_lt_(B,Z,Ls,Rs), % Ls = [Z|Rs],
less_than(Zs,Rs,X). % less_than(Zs,Rs,X). % Ls = Rs),
% % less_than(Zs,Rs,X).
ord_lt_(<,Z,[Z|Ls],Ls). % incl_lt_(true ,Z,[Z|Ls],Ls). %
ord_lt_(=,_, Ls ,Ls). % incl_lt_(false,_, Ls ,Ls). %
ord_lt_(>,_, Ls ,Ls). % %
Next, let's use dcg!
In the right column we use if_//3 instead of if_/3.
Note the different argument orders of dcg and non-dcg solutions: less_than([1,2,3],Zs,3) vs phrase(less_than([1,2,3],3),Zs).
The following dcg implementations correspond to above non-dcg codes:
less_than([],_) --> []. % less_than([],_) --> []. % less_than([],_) --> [].
less_than([Z|Zs],X) --> % less_than([Z|Zs],X) --> % less_than([Z|Zs],X) -->
{ zcompare(Ord,Z,X) }, % { #<(Z,X,B) }, % if_(Z #< X,[Z],[]),
ord_lt_(Ord,Z), % incl_lt_(B,Z), % less_than(Zs,X).
less_than(Zs,X). % less_than(Zs,X). %
% %
ord_lt_(<,Z) --> [Z]. % incl_lt_(true ,Z) --> [Z]. %
ord_lt_(=,_) --> []. % incl_lt_(false,_) --> []. %
ord_lt_(>,_) --> []. % %
OK! Saving the best for last... Simply use meta-predicate tfilter/3 together with (#>)/3!
less_than(Xs,Zs,P) :-
tfilter(#>(P),Xs,Zs).
The dcg variant in this previous answer is our starting point.
Consider the auxiliary non-terminal ord_lt_//2:
ord_lt_(<,Z) --> [Z].
ord_lt_(=,_) --> [].
ord_lt_(>,_) --> [].
These three clauses can be covered using two conditions:
Ord = (<): the item should be included.
dif(Ord, (<)): it should not be included.
We can express this "either-or choice" using if_//3:
less_than([],_) --> [].
less_than([Z|Zs],X) -->
{ zcompare(Ord,Z,X) },
if_(Ord = (<), [Z], []),
less_than(Zs,X).
Thus ord_lt_//2 becomes redundant.
Net gain? 3 lines-of-code !-)

prolog list of how many times an element occurs in a list?

Well, I have a list, say [a,b,c,c,d], and I want to generate a list [[a,1],[b,1],[c,2],[d,1]]. But I'm having trouble with generating my list. I can count how many times the element occur but not add it into a list:
% count how much the element occurs in the list.
count([], _, 0).
count([A|Tail], A, K) :-
count(Tail, A, K1),
K is K1 + 1.
count([_|Tail], X, K) :-
count(Tail, X, K1),
K is K1 + 0.
% Give back a list with each element and how many times is occur
count_list(L, [], _).
count_list(L, [A|Tail], Out) :-
count(L, A, K),
write(K),
count_list(L, Tail, [K|Out]).
I'm trying to learn Prolog but having some difficulties... Some help will be much appreciated... Thanks in advance!
Let me first refer to a related question "How to count number of element occurrences in a list in Prolog" and to my answer in particular.
In said answer I presented a logically-pure monotone implementation of a predicate named list_counts/2, which basically does what you want. Consider the following query:
?- list_counts([a,b,c,c,d], Xs).
Xs = [a-1,b-1,c-2,d-1]. % succeeds deterministically
?- list_counts([a,b,a,d,a], Xs). % 'a' is spread over the list
Xs = [a-3,b-1,d-1]. % succeeds deterministically
Note that the implementation is monotone and gives logically sound answers even for very general queries like the following one:
?- Xs = [_,_,_,_],list_counts(Xs,[a-N,b-M]).
Xs = [a,a,a,b], N = 3, M = 1 ;
Xs = [a,a,b,a], N = 3, M = 1 ;
Xs = [a,a,b,b], N = M, M = 2 ;
Xs = [a,b,a,a], N = 3, M = 1 ;
Xs = [a,b,a,b], N = M, M = 2 ;
Xs = [a,b,b,a], N = M, M = 2 ;
Xs = [a,b,b,b], N = 1, M = 3 ;
false.
I cannot follow your logic. The easy way would be to use library(aggregate), but here is a recursive definition
count_list([], []).
count_list([H|T], R) :-
count_list(T, C),
update(H, C, R).
update(H, [], [[H,1]]).
update(H, [[H,N]|T], [[H,M]|T]) :- !, M is N+1.
update(H, [S|T], [S|U]) :- update(H, T, U).
the quirk: it build the result in reverse order. Your code, since it uses an accumulator, would give the chance to build in direct order....

Prolog program that deletes every n-th element from a list

Could you help me solve the following?
Write a ternary predicate delete_nth that deletes every n-th element from a list.
Sample runs:
?‐ delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e] ;
false
?‐ delete_nth([a,b,c,d,e,f],1,L).
L = [] ;
false
?‐ delete_nth([a,b,c,d,e,f],0,L).
false
I tried this:
listnum([],0).
listnum([_|L],N) :-
listnum(L,N1),
N is N1+1.
delete_nth([],_,_).
delete_nth([X|L],C,L1) :-
listnum(L,S),
Num is S+1,
( C>0
-> Y is round(Num/C),Y=0
-> delete_nth(L,C,L1)
; delete_nth(L,C,[X|L1])
).
My slightly extravagant variant:
delete_nth(L, N, R) :-
N > 0, % Added to conform "?‐ delete_nth([a,b,c,d,e,f],0,L). false"
( N1 is N - 1, length(Begin, N1), append(Begin, [_|Rest], L) ->
delete_nth(Rest, N, RestNew), append(Begin, RestNew, R)
;
R = L
).
Let's use clpfd! For the sake of versatility and tons of other good reasons:
:- use_module(library(clpfd)).
We define delete_nth/3 based on if_/3 and (#>=)/3:
delete_nth(Xs,N,Ys) :-
N #> 0,
every_tmp_nth_deleted(Xs,0,N,Ys).
every_tmp_nth_deleted([] ,_ ,_,[] ). % internal auxiliary predicate
every_tmp_nth_deleted([X|Xs],N0,N,Ys0) :-
N1 is N0+1,
if_(N1 #>= N,
(N2 = 0, Ys0 = Ys ),
(N2 = N1, Ys0 = [X|Ys])),
every_tmp_nth_deleted(Xs,N2,N,Ys).
Sample query:
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],2,Ys).
Ys = [1,3,5,7,9,11,13,15] % succeeds deterministically
Ok, how about something a little more general?
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],N,Ys).
N = 1 , Ys = []
; N = 2 , Ys = [1, 3, 5, 7, 9, 11, 13, 15]
; N = 3 , Ys = [1,2, 4,5, 7,8, 10,11, 13,14 ]
; N = 4 , Ys = [1,2,3, 5,6,7, 9,10,11, 13,14,15]
; N = 5 , Ys = [1,2,3,4, 6,7,8,9, 11,12,13,14 ]
; N = 6 , Ys = [1,2,3,4,5, 7,8,9,10,11, 13,14,15]
; N = 7 , Ys = [1,2,3,4,5,6, 8,9,10,11,12,13, 15]
; N = 8 , Ys = [1,2,3,4,5,6,7, 9,10,11,12,13,14,15]
; N = 9 , Ys = [1,2,3,4,5,6,7,8, 10,11,12,13,14,15]
; N = 10 , Ys = [1,2,3,4,5,6,7,8,9, 11,12,13,14,15]
; N = 11 , Ys = [1,2,3,4,5,6,7,8,9,10, 12,13,14,15]
; N = 12 , Ys = [1,2,3,4,5,6,7,8,9,10,11, 13,14,15]
; N = 13 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12, 14,15]
; N = 14 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13, 15]
; N = 15 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14 ]
; N in 16..sup, Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].
Please follow aBathologist instructive answer and explanation (+1). I just post my own bet at solution since there is a problem in ditto solution for ?‐ delete_nth([a,b,c,d,e,f],0,L)..
delete_nth(L,C,R) :-
delete_nth(L,C,1,R).
delete_nth([],_,_,[]).
delete_nth([_|T],C,C,T1) :- !, delete_nth(T,C,1,T1).
delete_nth([H|T],N,C,[H|T1]) :- C<N, C1 is C+1, delete_nth(T,N,C1,T1).
yields
1 ?- delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e].
2 ?- delete_nth([a,b,c,d,e,f],1,L).
L = [].
3 ?- delete_nth([a,b,c,d,e,f],0,L).
false.
A minor (?) problem: this code is deterministic, while the samples posted apparently are not (you have to input ';' to get a false at end). Removing the cut will yield the same behaviour.
An interesting - imho - one liner variant:
delete_nth(L,C,R) :- findall(E, (nth1(I,L,E),I mod C =\= 0), R).
but the C==0 must be ruled out, to avoid
ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor'
Edited, correcting the mistake pointed out by #CapelliC, where predicate would succeed on N = 0.
I can see where you're headed with your solution, but you needn't bother with so much arithmetic in this case. We can delete the Nth element by counting down from N repeatedly until the list is empty. First, a quick note about style:
If you use spaces, line breaks, and proper placement of parenthesis you can help your readers parse your code. Your last clause is much more readable in this form:
delete_nth([X|L], C, L1):-
listnum(L, S),
Num is S+1,
C>0 -> Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1]).
Viewing your code now, I'm not sure whether you meant to write
( C>0 -> ( Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1) )
; delete_nth(L, C, [X|L1])
).
or if you meant
C>0 -> Y is round(Num/C),
( Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1])
).
or perhaps you're missing a ; before the second conditional? In any case, I suggest another approach...
This looks like a job for auxiliary predicates!
Often, we only need a simple relationship in order to pose a query, but the computational process necessary to resolve the query and arrive at an answer calls for a more complex relation. These are cases where it is "easier said than done".
My solution to this problem works as follows: In order to delete every nth element, we start at N and count down to 1. Each time we decrement the value from N, we move an element from the original list to the list of elements we're keeping. When we arrive at 1, we discard the element from our original list, and start counting down from N again. As you can see, in order to ask the question "What is the list Kept resulting from dropping every Nth element of List?" we only need three variables. But my answer the question, also requires another variable to track the count-down from N to 1, because each time we take the head off of List, we need to ask "What is the Count?" and once we've reached 1, we need to be able to remember the original value of N.
Thus, the solution I offer relies on an auxiliary, 4-place predicate to do the computation, with a 3-place predicate as the "front end", i.e., as the predicate used for posing the question.
delete_nth(List, N, Kept) :-
N > 0, %% Will fail if N < 0.
delete_nth(List, N, N, Kept), !. %% The first N will be our our counter, the second our target value. I cut because there's only one way to generate `Kept` and we don't need alternate solutions.
delete_nth([], _, _, []). %% An empty list has nothing to delete.
delete_nth([_|Xs], 1, N, Kept) :- %% When counter reaches 1, the head is discarded.
delete_nth(Xs, N, N, Kept). %% Reset the counter to N.
delete_nth([X|Xs], Counter, N, [X|Kept]) :- %% Keep X if counter is still counting down.
NextCount is Counter - 1, %% Decrement the counter.
delete_nth(Xs, NextCount, N, Kept). %% Keep deleting elements from Xs...
Yet another approach, following up on #user3598120 initial impulse to calculate the undesirable Nth elements away and inspired by #Sergey Dymchenko playfulness. It uses exclude/3 to remove all elements at a 1-based index that is multiple of N
delete_nth(List, N, Kept) :-
N > 0,
exclude(index_multiple_of(N, List), List, Kept).
index_multiple_of(N, List, Element) :-
nth1(Index, List, Element),
0 is Index mod N.

How can I remove the last n elements from a list in Prolog?

I would like to delete the last n elements of a list in Prolog and put it in another list say L2. If I knew the exact number of elements to delete say 3, here is the code. But I am stuck with the variable n case. Btw I would like to return an empty string if the length of the list is shorter than n. Thank you.
without_last_three([], []).
without_last_three([_], []).
without_last_three([_,_], []).
without_last_three([_,_,_], []).
without_last_three([Head|Tail], [Head|NTail]):-
without_last_three(Tail, NTail).
without_last_n(Old, N, New) :-
length(Tail, N),
append(New, Tail, Old).
Test run:
?- without_last_n([a, b, c, d, e, f], 4, New).
New = [a, b]
?- without_last_n([a, b, c, d, e, f], 777, New).
false.
?- without_last_n([a, b, c, d, e, f], 0, New).
New = [a, b, c, d, e, f]
Update. To succeed with an [] when N is bigger than the length of the list, second clause can be added:
without_last_n(Old, N, []) :-
length(Old, L),
N > L.
Here is a general case:
without_last_n(L, N, []) :-
nonvar(L), nonvar(N),
length(L, M),
N > M.
without_last_n(L, N, R) :-
without_last_n_(L, N, R).
without_last_n_(L, N, []) :-
length(L, N).
without_last_n_([H|T], N, [H|T1]) :-
without_last_n_(T, N, T1).
This satisfies the given requirements, and works with a variety of variable instantiation scenarios. What complicates the solution a bit is the requirement that without_last_n(L, N, []). must succeed if N is greater than the length of L. If this was not a requirement, then the much simpler without_last_n_/3 would suffice as a solution to the problem.
Testing...
| ?- without_last_n([1,2,3,4], 3, R).
R = [1] ? ;
no
| ?- without_last_n([1,2,3,4], N, R).
N = 4
R = [] ? ;
N = 3
R = [1] ? ;
N = 2
R = [1,2] ? ;
N = 1
R = [1,2,3] ? ;
N = 0
R = [1,2,3,4]
(1 ms) yes
| ?- without_last_n([1,2,3,4], N, [1,2]).
N = 2 ? ;
no
| ?- without_last_n(L, 3, [1,2]).
L = [1,2,_,_,_] ? ;
no
| ?- without_last_n(L, 2, R).
L = [_,_]
R = [] ? ;
L = [A,_,_]
R = [A] ? ;
L = [A,B,_,_]
R = [A,B] ? ;
L = [A,B,C,_,_]
R = [A,B,C] ?
...
| ?- without_last_n(L, N, [1,2]).
L = [1,2]
N = 0 ? ;
L = [1,2,_]
N = 1 ? ;
L = [1,2,_,_]
N = 2 ? ;
...
| ?- without_last_n(L, N, R).
L = []
N = 0
R = [] ? ;
L = [_]
N = 1
R = [] ? ;
L = [_,_]
N = 2
R = [] ? ;
L = [_,_,_]
N = 3
R = [] ? ;
...
| ?-
A possible flaw here is that without_last_n([1,2,3,4], N, R). perhaps could generate solutions ad infinitum of N = 5, R = [], N = 6, R = [], etc. But it doesn't. Left as an exercise for the reader. :)