Since you are using Prolog (;) / 2 - if-then-else for the task, you may need if_ / 3 . In addition, the predicate can be made more universal by using CLP (FD) (for details, see, for example, Swi-Prolog manual writing to CLP (FD) ). And, in addition, I would suggest using a call predicate with two arguments, namely a list and a list of gradually increasing elements. To emphasize the relational nature of the predicate, give it a more descriptive name, for example list_ascendings / 2:
:- use_module(library(clpfd)). list_ascendings([],[]). list_ascendings([X|Xs],A) :- X0
The first rule list_ascendings / 2 is for handling an empty list. If you do not want to include this case, just omit the rule. The second rule calls the predicate list_ascendings_ / 3 with a rotation value ( X0 ) that is smaller than the list title, so the latter is included in the list of gradually increasing elements. The defensive version of a higher ratio (used as the first argument to if_ / 3 ) can be defined as follows:
bool_t(1,true). bool_t(0,false). #<(X,Y,Truth) :- X #< Y #<==> B, bool_t(B,Truth).
Based on this, a predicate describing the actual relationship can be defined as follows:
list_ascendings_([],[],_). list_ascendings_([X|Xs],A,X0) :- if_(X0#<X, (A=[X|As], X1=X), (A=As, X1=X0)), list_ascendings_(Xs,As,X1).
Depending on whether the rotation value of the header head is less or not, the list of ascending elements ( A ) and the new rotation value ( X1 ) are described respectively.
Now let's see how the predicate works. Your sample query gives the desired result:
?- list_ascendings([1,5,2,3,4,10,15,11,12,13,20],A). A = [1,5,10,15,20]
Note that the predicate deterministically succeeds if the first argument is grounded (no selection points remain open, so no need to click ; after a single solution). You can also ask the opposite question: which lists have [1,5,10,15,20] as the largest gradually increasing sublist?
?- list_ascendings(L,[1,5,10,15,20]). L = [1,5,10,15,20] ? ; L = [1,5,10,15,20,_A], _A in inf..20 ? ; L = [1,5,10,15,20,_A,_B], _A in inf..20, _B in inf..20 ? ...
Obviously, there are infinitely many answers to this question. However, it would be nice to get the answers in a more equitable order, that is, all answers for lists of length 6 before lists of length 7, etc. You can achieve this by pre-setting the query with a target length of / 2:
?- length(L,_), list_ascendings(L,[1,5,10,15,20]). L = [1,5,10,15,20] ? ; L = [1,5,10,15,20,_A], _A in inf..20 ? ; L = [1,5,10,15,_A,20], _A in inf..15 ? ; L = [1,5,10,_A,15,20], _A in inf..10 ? ; ... L = [1,5,10,15,20,_A,_B], _A in inf..20, _B in inf..20 ? ; L = [1,5,10,15,_A,20,_B], _A in inf..15, _B in inf..20 ? ; L = [1,5,10,15,_A,_B,20], _A in inf..15, _B in inf..15 ? ; ...
You can also get answers with specific numbers by restricting the L elements to a domain using ins / 2 and labeling it. For example: what lists of length 7 and numbers from 0 to 20 are such that [1,5,10,15,20] is the largest ascending ascending list? The corresponding request provides all the answers for 1997:
?- length(L,7), L ins 0..20, list_ascendings(L,[1,5,10,15,20]), label(L). L = [1,5,10,15,20,0,0] ? ; L = [1,5,10,15,20,0,1] ? ; L = [1,5,10,15,20,0,2] ? ; ... L = [1,5,10,15,20,2,15] ? ; ... L = [1,0,5,10,4,15,20] ? ; ...
EDIT:
As for your question in the comments, the description of the gradual descending sublist is pretty simple coming from the upstream version. You just need to slightly modify two goals:
list_descendings([],[]). list_descendings([X|Xs],A) :- X0
This gives the desired result:
?- list_descendings([20,15,3,5,7,8,2,6,2],A). A = [20,15,3,2]
On the other hand, if you mean one predicate that does both (see the last query below), you need a few more changes. First you need to add an update version of the relationship for the downstream sublists:
#>(X,Y,Truth) :- X #> Y #<==> B, bool_t(B,Truth).
Since the first rotation value is calculated differently for the ascending and descending sublists, it is oppurtune to delegate that to the new predicate:
x_pivot_wrt(X,X0,
Then the calling predicate needs an additional argument to indicate in what respect the sub-list should progress. It would also be beneficial to rename it to reflect its new behavior:
list_progressives_wrt([],[],_). list_progressives_wrt([X|Xs],P,Rel) :- x_pivot_wrt(X,X0,Rel), list_progressives_wrt_([X|Xs],P,Rel,X0).
Finally, the predicate describing the actual relation also has an additional argument, namely the relation indicated. The first if_ / 3 argument calls the specified relation ( Rel ) along with the rotation value ( X0 ) and the head of the list ( X ). Note that the last argument (true value) is missing in the call, as is the first if_ / 3 argument in list_ascendings_ / 3 and list_descendings_ / 3.
list_progressives_wrt_([],[],_,_). list_progressives_wrt_([X|Xs],P,Rel,X0) :- if_(call(Rel,X0,X), (P=[X|Ps], X1=X), (P=Ps, X1=X0)), list_progressives_wrt_(Xs,Ps,Rel,X1).
A query that matches your example produces the desired result:
?- list_progressives_wrt([1,5,2,3,4,10,15,11,12,13,20],P,
Since relationships that can be specified appear in x_pivot_wrt / 3, you can specify both options by leaving the last argument variable:
?- list_progressives_wrt([20,15,3,21,5,7,8,2,6,30,2],P,Rel). P = [20,15,3,2], Rel =