Related
Eliminate consecutive duplicates of list elements.
My solution for this is:
compress([X,X|Xs], Q) :-
compress([X|Xs], Q).
compress([X,Y|Xs], Q) :-
X \= Y,
compress([Y|Xs], QR),
append([X], QR, Q).
compress([X|[]], Q) :-
compress([], QR),
append([X], QR, Q).
compress([], []).
And, because of the fact I am beginner and I have no experience in a logic paradigm I ask you for say what I can improve and why my solution is not good as it can be.
For example, X \= Y doesn't look pretty to me.
We start with the name of the predicate.
Why do you use an imperative to denote a relation? A good Prolog program is usable in all directions, whereas an imperative always suggests a particular direction or mode of use. Therefore, choose a declarative name and aim for generality and logical-purity.
Next, what about the most general query:
?- compress(Ls, Cs).
ERROR: Out of local stack
Not very nice! We expect this to yield at least a few answers.
What if we use iterative deepening:
?- length(Ls, _), compress(Ls, Cs).
Ls = Cs, Cs = [] ;
Ls = Cs, Cs = [_G841] ;
Ls = [_G841, _G841],
Cs = [_G841] ;
Ls = [_G841, _G841, _G841],
Cs = [_G841] .
Hm! Quite a few answers are missing! What about the case where the elements are different? As you already intuitively expect, it is the use of impure predicates that leads to such effects.
Therefore, use prolog-dif, i.e., dif/2, to denote that two terms are different. It's usable in all directions!
Moreover, DCGs (dcg) are often useful when describing lists.
So, in total, what about this:
compression([]) --> [].
compression([L|Ls]) --> [L], compression_(Ls, L).
compression_([], _) --> [].
compression_([X|Xs], L) -->
( { X = L },
compression_(Xs, L)
; { dif(X, L) },
[X],
compression_(Xs, X)
).
We use the interface predicate phrase/2 to work with the DCG.
Usage examples:
?- phrase(compression(Ls), Cs).
Ls = Cs, Cs = [] ;
Ls = Cs, Cs = [_G815] ;
Ls = [_G815, _G815],
Cs = [_G815] .
?- length(Ls, _), phrase(compression(Ls), Cs).
Ls = Cs, Cs = [] ;
Ls = Cs, Cs = [_G865] ;
Ls = [_G865, _G865],
Cs = [_G865] ;
Ls = Cs, Cs = [_G1111, _G1114],
dif(_G1114, _G1111) .
Take it from here! Improve determinism, find an even better name etc.
Building on the answer by #mat (+1), why not improve determinacy for cases like this one:
?- phrase(compression([a,a,b,b,b,c,c,c,c,d]), Xs).
Xs = [a, b, c, d] ;
false.
With ; false the SWI prolog-toplevel indicates that the goal did not succeed deterministically.
We can improve compression_//2 by using if_//3—the dcg analogue of if_/3:
compression_([], _) --> [].
compression_([X|Xs], L) -->
if_(X = L, % is this item equal to previous one?
compression_(Xs, L), % yes: old "run" goes on
([X], compression_(Xs, X))). % no: new "run" starts
Sample query:
?- phrase(compression([a,a,b,b,b,c,c,c,c,d]), Xs).
Xs = [a, b, c, d]. % succeeds deterministically
I can make lists of ascending integer like so:
?- findall(L,between(1,5,L),List).
I know I can also generate values using:
?- length(_,X).
But I don't think I can use this in a findall, as things like the following loop:
?- findall(X,(length(_,X),X<6),Xs).
I can also generate a list using clpfd.
:- use_module(library(clpfd)).
list_to_n(N,List) :-
length(List,N),
List ins 1..N,
all_different(List),
once(label(List)).
or
list_to_n2(N,List) :-
length(List,N),
List ins 1..N,
chain(List,#<),
label(List).
The last method seems best to me as it is the most declarative, and does not use once/1 or between/3 or findall/3 etc.
Are there other ways to do this? Is there a declarative way to do this in 'pure' Prolog? Is there a 'best' way?
The "best" way depends on your concrete use cases! Here's another way to do it using clpfd:
:- use_module(library(clpfd)).
We define predicate equidistant_stride/2 as suggested by #mat in a comment to a previous answer of a related question:
equidistant_stride([],_).
equidistant_stride([Z|Zs],D) :-
foldl(equidistant_stride_(D),Zs,Z,_).
equidistant_stride_(D,Z1,Z0,Z1) :-
Z1 #= Z0+D.
Based on equidistant_stride/2, we define:
consecutive_ascending_integers(Zs) :-
equidistant_stride(Zs,1).
consecutive_ascending_integers_from(Zs,Z0) :-
Zs = [Z0|_],
consecutive_ascending_integers(Zs).
consecutive_ascending_integers_from_1(Zs) :-
consecutive_ascending_integers_from(Zs,1).
Let's run some queries! First, your original use case:
?- length(Zs,N), consecutive_ascending_integers_from_1(Zs).
N = 1, Zs = [1]
; N = 2, Zs = [1,2]
; N = 3, Zs = [1,2,3]
; N = 4, Zs = [1,2,3,4]
; N = 5, Zs = [1,2,3,4,5]
...
With clpfd, we can ask quite general queries—and get logically sound answers, too!
?- consecutive_ascending_integers([A,B,0,D,E]).
A = -2, B = -1, D = 1, E = 2.
?- consecutive_ascending_integers([A,B,C,D,E]).
A+1#=B, B+1#=C, C+1#=D, D+1#=E.
An alternative implementation of equidistant_stride/2:
I hope the new code makes better use of constraint propagation.
Thanks to #WillNess for suggesting the test-cases that motivated this rewrite!
equidistant_from_nth_stride([],_,_,_).
equidistant_from_nth_stride([Z|Zs],Z0,N,D) :-
Z #= Z0 + N*D,
N1 #= N+1,
equidistant_from_nth_stride(Zs,Z0,N1,D).
equidistant_stride([],_).
equidistant_stride([Z0|Zs],D) :-
equidistant_from_nth_stride(Zs,Z0,1,D).
Comparison of old vs new version with #mat's clpfd:
First up, the old version:
?- equidistant_stride([1,_,_,_,14],D).
_G1133+D#=14,
_G1145+D#=_G1133,
_G1157+D#=_G1145,
1+D#=_G1157. % succeeds with Scheinlösung
?- equidistant_stride([1,_,_,_,14|_],D).
_G1136+D#=14, _G1148+D#=_G1136, _G1160+D#=_G1148, 1+D#=_G1160
; 14+D#=_G1340, _G1354+D#=14, _G1366+D#=_G1354, _G1378+D#=_G1366, 1+D#=_G1378
... % does not terminate universally
Now let's switch to the new version and ask the same queries!
?- equidistant_stride([1,_,_,_,14],D).
false. % fails, as it should
?- equidistant_stride([1,_,_,_,14|_],D).
false. % fails, as it should
More, now, again! Can we fail earlier by tentatively employing redundant constraints?
Previously, we proposed using constraints Z1 #= Z0+D*1, Z2 #= Z0+D*2, Z3 #= Z0+D*3 instead of Z1 #= Z0+D, Z2 #= Z1+D, Z3 #= Z2+D
(which the 1st version of code in this answer did).
Again, thanks to #WillNess for motivating this little experiment by
noting that the goal equidistant_stride([_,4,_,_,14],D) does not fail but instead succeeds with pending goals:
?- Zs = [_,4,_,_,14], equidistant_stride(Zs,D).
Zs = [_G2650, 4, _G2656, _G2659, 14],
14#=_G2650+4*D,
_G2659#=_G2650+3*D,
_G2656#=_G2650+2*D,
_G2650+D#=4.
Let's add some redundant constraints with equidistantRED_stride/2:
equidistantRED_stride([],_).
equidistantRED_stride([Z|Zs],D) :-
equidistant_from_nth_stride(Zs,Z,1,D),
equidistantRED_stride(Zs,D).
Sample query:
?- Zs = [_,4,_,_,14], equidistant_stride(Zs,D), equidistantRED_stride(Zs,D).
false.
Done? Not yet! In general we don't want a quadratic number of redundant constraints. Here's why:
?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D).
Zs = [_G2683, _G2686, _G2689, _G2692, 14],
14#=_G2683+4*D,
_G2692#=_G2683+3*D,
_G2689#=_G2683+2*D,
_G2686#=_G2683+D.
?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D), equidistantRED_stride(Zs,D).
Zs = [_G831, _G834, _G837, _G840, 14],
14#=_G831+4*D,
_G840#=_G831+3*D,
_G837#=_G831+2*D,
_G834#=_G831+D,
14#=_G831+4*D,
_G840#=_G831+3*D,
_G837#=_G831+2*D,
_G834#=_G831+D,
D+_G840#=14,
14#=2*D+_G837,
_G840#=D+_G837,
14#=_G834+3*D,
_G840#=_G834+2*D,
_G837#=_G834+D.
But if we use the double-negation trick, the residuum remains in cases that succeed ...
?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D), \+ \+ equidistantRED_stride(Zs,D).
Zs = [_G454, _G457, _G460, _G463, 14],
14#=_G454+4*D,
_G463#=_G454+3*D,
_G460#=_G454+2*D,
_G457#=_G454+D.
... and ...
?- Zs = [_,4,_,_,14], equidistant_stride(Zs,D), \+ \+ equidistantRED_stride(Zs,D).
false.
... we detect failure in more cases than we did before!
Let's dig a little deeper! Can we detect failure early in even more generalized uses?
With code presented so far, these two logically false queries do not terminate:
?- Zs = [_,4,_,_,14|_], \+ \+ equidistantRED_stride(Zs,D), equidistant_stride(Zs,D).
... % Execution Aborted
?- Zs = [_,4,_,_,14|_], equidistant_stride(Zs,D), \+ \+ equidistantRED_stride(Zs,D).
... % Execution Aborted
Got fix? Got hack!
?- use_module(library(lambda)).
true.
?- Zs = [_,4,_,_,14|_],
\+ ( term_variables(Zs,Vs),
maplist(\X^when(nonvar(X),integer(X)),Vs),
\+ equidistantRED_stride(Zs,D)),
equidistant_stride(Zs,D).
false.
The hack doesn't guarantee termination of the redundant constraint "part", but IMO it's not too bad for a quick first shot. The test integer/1 upon instantiation of any variable in Zs is meant to allow the clpfd solver to constrain variable domains to singletons, while the instantiation with cons-pairs (which directly leads to non-termination of list-based predicates) is suppressed.
I do realize that the hack can be broken quite easily in more than one way (e.g., using cyclic terms). Any suggestions and comments are welcome!
In the following we discuss the code presented in this previous answer.
The goal consecutive_ascending_integers_from_1([2,3,5,8|non_list]) fails, but why?
Let's proceed step-by-step:
Here's the code we start with:
:- use_module(library(clpfd)).
equidistant_from_nth_stride([],_,_,_).
equidistant_from_nth_stride([Z|Zs],Z0,I0,D) :-
Z #= Z0 + I0*D,
I1 #= I0 + 1,
equidistant_from_nth_stride(Zs,Z0,I1,D).
equidistant_stride([],_).
equidistant_stride([Z0|Zs],D) :-
equidistant_from_nth_stride(Zs,Z0,1,D).
consecutive_ascending_integers(Zs) :-
equidistant_stride(Zs,1).
consecutive_ascending_integers_from(Zs,Z0) :-
Zs = [Z0|_],
consecutive_ascending_integers(Zs).
consecutive_ascending_integers_from_1(Zs) :-
consecutive_ascending_integers_from(Zs,1).
First, we make (some) unifications more explicit:
equidistant_from_nth_stride([],_,_,_).
equidistant_from_nth_stride([Z|Zs],Z0,I0,D) :-
Z #= Z0 + I0*D,
I1 #= I0 + 1,
equidistant_from_nth_stride(Zs,Z0,I1,D).
equidistant_stride([],_).
equidistant_stride([Z0|Zs],D) :-
I = 1,
equidistant_from_nth_stride(Zs,Z0,I,D).
consecutive_ascending_integers(Zs) :-
D = 1,
equidistant_stride(Zs,D).
consecutive_ascending_integers_from(Zs,Z0) :-
Zs = [Z0|_],
consecutive_ascending_integers(Zs).
consecutive_ascending_integers_from_1(Zs) :-
Z0 = 1,
consecutive_ascending_integers_from(Zs,Z0).
We follow the method and conventions introduced in this fine answer:
By removing goals, we can generalize a program. Here is my favorite way to do it. By adding a predicate (*)/1 like so:
:- op(950,fy, *).
*_.
#WillNess rightly noted that:
consecutive_ascending_integers_from_1([2|_]) fails, so its specialization consecutive_ascending_integers_from_1([2,3,5,8|non_list]) must fail too.
If maximally generalize the code so that consecutive_ascending_integers_from_1([2|_]) fails, we "know for sure: something in the visible remaining part of the program has to be fixed."
consecutive_ascending_integers_from(Zs,Z0) :-
Zs = [Z0|_],
* consecutive_ascending_integers(Zs).
consecutive_ascending_integers_from_1(Zs) :-
Start = 1,
consecutive_ascending_integers_from(Zs,Start).
Let's have another explanation!
With version #2 (see above), we observe the following generalized goal fails, too:
?- consecutive_ascending_integers_from_1([_,_,_,_|non_list]).
false.
Why does this fail? Let's maximally generalize the code suchthat the goal fails:
equidistant_from_nth_stride([],_,_,_).
equidistant_from_nth_stride([Z|Zs],Z0,I0,D) :-
* Z #= Z0 + I0*D,
* I1 #= I0 + 1,
equidistant_from_nth_stride(Zs,Z0,I1,D).
equidistant_stride([],_).
equidistant_stride([Z0|Zs],D) :-
* I = 1,
equidistant_from_nth_stride(Zs,Z0,I,D).
consecutive_ascending_integers(Zs) :-
* D = 1,
equidistant_stride(Zs,D).
consecutive_ascending_integers_from(Zs,Z0) :-
* Zs = [Z0|_],
consecutive_ascending_integers(Zs).
consecutive_ascending_integers_from_1(Zs) :-
* Start = 1,
consecutive_ascending_integers_from(Zs,Start).
Why does the goal consecutive_ascending_integers_from_1([2,3,5,8|non_list]) fail?
Up to now, we have seen two explanations, but there may be more...
The truth is out there: Join the hunt!
We'll define ascending lists as such that contain at least two elements which are increasing integer numbers (non-decreasing lists could be empty, or singleton, but "ascending" is a more definite property). It's a somewhat arbitrary determination.
In SWI Prolog:
ascending( [A,B|R] ):-
freeze(A,
freeze(B, (A < B, freeze(R, (R=[] -> true ; ascending([B|R])))) )).
To easily fill'em up, we could use
mselect([A|B],S,S2):- select(A,S,S1), mselect(B,S1,S2).
mselect([], S2, S2).
Testing:
15 ?- ascending(LS),mselect(LS,[10,2,8,5],[]).
LS = [2, 5, 8, 10] ;
false.
16 ?- mselect(LS,[10,2,8,5],[]), ascending(LS).
LS = [2, 5, 8, 10] ;
false.
As to the bounty question, according to https://stackoverflow.com/tags/logical-purity/info,
Only monotonic (also called: "monotone") predicates are pure: If the predicate succeeds for any arguments, then it does not fail for any generalization of these arguments, and if it fails for any combination of arguments, then it does not succeed for any specialization of these arguments.
consecutive_ascending_integers_from_1([2|B]) fails, so its specialization consecutive_ascending_integers_from_1([2,3,5,8|non_list]) must fail too.
For the extended bounty " consecutive_ascending_integers_from_1([2,3,5,8|non_list]) fails, but why?", additional failing goals are: ( 1 )
consecutive_ascending_integers_from_1([_,3|_])
for the code
equidistant_from_nth_stride([],_,_,_).
equidistant_from_nth_stride([Z|Zs],Z0,I0,D) :-
Z #= Z0 + I0*D, % C1
*( I1 #= I0 + 1 ),
equidistant_from_nth_stride(Zs,Z0,I1,D).
and the rest unchanged, because C1 becomes 3 #= 1 + 1*1. Also, ( 2 and 3 )
consecutive_ascending_integers_from_1([A,B,5|_])
consecutive_ascending_integers_from_1([A,B,C,8|_])
both fail with the unchanged code, because the 1st defines
A = 1, B #= 1 + 1*1, 5 #= 1 + 2*1
and the 2nd defines
A = 1, B #= 1 + 1*1, C #= 1 + 2*1, 8 #= 1 + 3*1
Yet another possibility ( 4 ) is
consecutive_ascending_integers_from_1([_,3,5|_])
with the generalized
consecutive_ascending_integers_from_1(Zs) :-
*( Z0 = 1 ),
consecutive_ascending_integers_from(Zs,Z0).
consecutive_ascending_integers_from(Zs,Z0) :-
*( Zs = [Z0|_] ),
consecutive_ascending_integers(Zs).
because
26 ?- 3 #= Z + 1*1, 5 #= Z + 2*1.
false.
Similarly, with the like modified code, the goal ( 5 )
consecutive_ascending_integers_from_1([_,3,_,8|_])
because
27 ?- 3 #= Z + 1*1, 8 #= Z + 3*1.
false.
and also the ( 6 ... 9 )
consecutive_ascending_integers_from_1([2,3,_,8|_])
consecutive_ascending_integers_from_1([2,_,_,8|_])
consecutive_ascending_integers_from_1([2,_,5,8|_])
consecutive_ascending_integers_from_1([2,_,5|_])
for the same reason. Yet another possible code generalization is to leave D uninitialized (with the rest of the original code unchanged):
consecutive_ascending_integers(Zs) :-
*( D = 1 ),
equidistant_stride(Zs,D).
so that the goal ( 5 ) ...[_,3,_,8|_]... again fails, because of
49 ?- 3 #= 1 + 1*D, 8 #= 1 + 3*D.
false.
but,
50 ?- 3 #= 1 + 1*D, 5 #= 1 + 2*D.
D = 2.
so ...[_,3,5|_]... would succeed (indeed it does). ( 10 )
consecutive_ascending_integers_from_1([_,_,5,8|_])
fails, as well, for the same reason.
There might be some more combinations, but the general gist of it becomes clearer: it all depends on how the constraints created by this predicate operate.
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 !-)
This is the code for deleting or removing an element from a given list:
remove_elem(X,[],[]).
remove_elem(X,L1,L2) :-
L1 = [H|T],
X == H,
remove_elem(X,T,Temp),
L2 = Temp.
remove_elem(X,L1,L2) :-
L1 = [H|T],
X \== H,
remove_elem(X,T,Temp),
L2 = [H|Temp].
How can I modify it, so that I can delete every occurrence of a sub list from a list?
When I tried to put a list in an element, it only deletes the element and only once.
It should be this:
?- remove([1,2],[1,2,3,4,1,2,5,6,1,2,1],L).
L = [3,4,5,6,1]. % expected result
Inspired by #CapelliC's implementation I wrote the following code based on
and_t/3:
append_t([] ,Ys,Ys, true).
append_t([X|Xs],Ys,Zs,Truth) :-
append_aux_t(Zs,Ys,Xs,X,Truth).
append_aux_t([] ,_ ,_ ,_,false). % aux pred for using 1st argument indexing
append_aux_t([Z|Zs],Ys,Xs,X,Truth) :-
and_t(X=Z, append_t(Xs,Ys,Zs), Truth).
One append_t/4 goal can replace two prefix_of_t/3 and append/3 goals.
Because of that, the implementation of list_sublist_removed/3 gets a bit simpler than before:
list_sublist_removed([] ,[_|_] ,[]).
list_sublist_removed([X|Xs],[L|Ls],Zs) :-
if_(append_t([L|Ls],Xs0,[X|Xs]),
(Zs = Zs0 , Xs1 = Xs0),
(Zs = [X|Zs0], Xs1 = Xs)),
list_sublist_removed(Xs1,[L|Ls],Zs0).
Still deterministic?
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
L = [3,4,5,6,1].
Yes! What about the following?
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],X,[3,4,5,6,1]).
X = [1,2] ; % succeeds with useless choice-point
false.
Nope. So there is still room for potential improvement...
This logically pure implementation is based on the predicates if_/3 and (=)/3.
First, we build a reified version of prefix_of/2:
prefix_of_t([],_,true).
prefix_of_t([X|Xs],Zs,T) :-
prefix_of_t__aux(Zs,X,Xs,T).
prefix_of_t__aux([],_,_,false).
prefix_of_t__aux([Z|Zs],X,Xs,T) :-
if_(X=Z, prefix_of_t(Xs,Zs,T), T=false).
Then, on to the main predicate list_sublist_removed/3:
list_sublist_removed([],[_|_],[]).
list_sublist_removed([X|Xs],[L|Ls],Zs) :-
if_(prefix_of_t([L|Ls],[X|Xs]), % test
(Zs = Zs0, append([L|Ls],Xs0,[X|Xs])), % case 1
(Zs = [X|Zs0], Xs0 = Xs)), % case 2
list_sublist_removed(Xs0,[L|Ls],Zs0).
A few operational notes on the recursive clause of list_sublist_removed/3:
First (test), we check if [L|Ls] is a prefix of [X|Xs].
If it is present (case 1), we strip it off [X|Xs] yielding Xs0 and add nothing to Zs.
If it is absent (case 2), we strip X off [X|Xs] and add X to Zs.
We recurse on the rest of [X|Xs] until no more items are left to process.
Onwards to some queries!
The use case you gave in your question:
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
L = [3,4,5,6,1]. % succeeds deterministically
Two queries that try to find the sublist that was removed:
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],Sub,[ 3,4,5,6,1]).
Sub = [1,2] ? ;
no
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],Sub,[1,3,4,5,6,1]).
no
Next, let's find a suitable Ls in this query:
?- list_sublist_removed(Ls,[1,2],[3,4,5,6,1]).
% a lot of time passes ... and nothing happens!
Non-termination! This is unfortunate, but within expectations, as the solution set is infinite. However, by a-priori constraining the length of Ls, we can get all expected results:
?- length(Ls,_), list_sublist_removed(Ls,[1,2],[3,4,5,6,1]).
Ls = [ 3,4,5,6,1] ?
; Ls = [1,2, 3,4,5,6,1] ?
; Ls = [3, 1,2, 4,5,6,1] ?
; Ls = [3,4, 1,2, 5,6,1] ?
; Ls = [3,4,5, 1,2, 6,1] ?
; Ls = [3,4,5,6, 1,2, 1] ?
; Ls = [3,4,5,6,1, 1,2 ] ?
; Ls = [1,2, 1,2, 3,4,5,6,1] ? ...
<rant>
So many years I study Prolog, still it deserves some surprises... your problem it's quite simple to solve, when you know the list library, and you have a specific mode (like the one you posted as example). But can also be also quite complex to generalize, and it's unclear to me if the approach proposed by #repeat, based on #false suggestion (if_/3 and friends) can be 'ported' to plain, old Prolog (a-la Clocksin-Mellish, just to say).
</rant>
A solution, that has been not so easy to find, based on old-school Prolog
list_sublist_removed(L, S, R) :-
append([A, S, B], L),
S \= [],
list_sublist_removed(B, S, T),
append(A, T, R),
!
; L = R.
some test:
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],[1,2],L).
L = [3, 4, 5, 6, 1].
?- list_sublist_removed([1,2,3,4,1,2,5,6,1,2,1],X,[3, 4, 5, 6, 1]).
X = [1, 2].
?- length(X,_), list_sublist_removed(X,[1,2],[3, 4, 5, 6, 1]).
X = [3, 4, 5, 6, 1] ;
X = [3, 4, 5, 6, 1, 2, 1] ...
Hi i was wondering if you could help me out with this
From programming in Prolog: write Prolog script for replacement any given element in lists by an another given element. For example:
replace( 3, a,[1,2,3,4,3,5], [1,2,a,4,a,5])=true
Many Thanks in advance
In Prolog, most list processing is done by processing the head and then recursively processing the rest of the list. Of course, you can't forget about the base case, which is an empty list.
Replacing anything with anything in an empty list results again in an empty list. If the head of the list is the same as the element to replace, replace it, otherwise, keep it as it is. In both cases, process recursively the rest of the list. Translated from English into Prolog:
replace(_, _, [], []).
replace(O, R, [O|T], [R|T2]) :- replace(O, R, T, T2).
replace(O, R, [H|T], [H|T2]) :- H \= O, replace(O, R, T, T2).
All implementations presented so far in other answers are logically unsound when being used with non-ground terms. Consider the original query and a slight variant:
?- replace(3,three,[1,2,3],Xs).
Xs = [1,2,three] ; % OK: correct
false
?- A=3, replace(A,B,[1,2,3],Xs). % OK: correct
Xs = [1,2,B], A = 3 ;
false
It works! Let's ask some very similar queries:
?- replace(A,B,[1,2,3],Xs). % FAIL: should succeed more than once...
Xs = [B,2,3], A = 1 ; % ... but the other solutions are missing
false
?- replace(A,B,[1,2,3],Xs), A=3. % FAIL: this query _should_ succeed ...
false % ... it does not!
What's going on? Put the blame on meta-logical builtins (!)/0 and (\=)/2, which are very hard to use right and often make code brittle, impure, and logically unsound.
To preserve logical soundness, stick to logical purity and abstain from meta-logical "features" whenever possible! Luckily, most Prolog implementations support dif/2 as a logical alternative to (\=)/2. Let's use it:
% code by #svick, modified to use dif/2 instead of (\=)/2
replaceP(_, _, [], []).
replaceP(O, R, [O|T], [R|T2]) :- replaceP(O, R, T, T2).
replaceP(O, R, [H|T], [H|T2]) :- dif(H,O), replaceP(O, R, T, T2).
Let's run above queries again, this time with the improved replaceP/4:
?- replaceP(3,three,[1,2,3],Xs).
Xs = [1,2,three] ; % OK: correct, like before
false
?- replaceP(A,B,[1,2,3],Xs). % OK: four solutions, not just one
Xs = [B,2,3], A = 1 ;
Xs = [1,B,3], A = 2 ;
Xs = [1,2,B], A = 3 ;
Xs = [1,2,3], dif(A,1),dif(A,2),dif(A,3) ;
false
?- replaceP(A,B,[1,2,3],Xs), A=3. % OK (succeeds now)
Xs = [1,2,B], A = 3 ;
false
?- A=3, replaceP(A,B,[1,2,3],Xs). % OK (same as before)
Xs = [1,2,B], A = 3 ;
false
replace(_, _ , [], []).
replace(X, Y, [ X | Z ], [ Y | ZZ]):- ! , replace( X, Y, Z, ZZ).
replace(X, Y, [ W | Z], [ W | ZZ] :- replace(X, Y, Z, ZZ).
Though, one would usually arrange the 3. arg to be the first one. And strictly speaking above does not replace anything in the list, it just anwsers if 4th arg is like the one in the 3rd but with Y' instead of X'.
replace(E,S,[],[]).
replace(E,S,[E|T1],[S|T2]):-replace(E,S,T1,T2).
replace(E,S,[H|T1],[H|T2]):-E\=H, replace(E,S,T1,T2).
the idea is simple, if the elements match, change it, if not, go forward until empty.
domains
I=integer*
K=integer*
Z=integer
A=integer
predicates
nondeterm rep(I,Z,A,K)
clauses
rep([],_,_,[]).
rep([Z|T1],Z,A,[A|T2]):- rep(T1,Z,A,T2).
rep([H|T1],Z,A,[H|T2]) :- rep(T1,Z,A,T2).
goal
rep([1,2,3],2,4,X).