How to create a infinite list if input is not delcared?

Viewed 97

I have a written a functional function that tells the user if a list is ordered or not, given the list inputted. However, if a user inputs a variable as the input instead of a list, I would like to output an infinite list. How can I go about this? Here is the current code

ordered([]).
ordered([_]).
ordered([X,Y|Ys]) :- X =< Y , ordered( [Y|Ys] ).

Here is some input

? ordered([1,2,3]).
true
? ordered([1,5,2]).
false

I also want for variables to creat infinite list like so

? ordered(L).
L = [];
L = [_1322] ;
L = [_1322, _1323] ;
L = [_1322, _1323, _1324] ;
L = [_1322, _1323, _1324, _1325].

The list should increase until the user exits as shown.

3 Answers

The list should increase until the user exits as shown.

Solution:

ordered([]).
ordered([_]).
ordered([X,Y|Ys]) :- X #=< Y , ordered( [Y|Ys] ). 

EDIT:

SWI Prolog doc

The arithmetic expression X is less than or equal to Y. When reasoning over integers, replace (=<)/2 by #=</2 to obtain more general relations. See declarative integer arithmetic (section A.9.3).

What properties should the list of variables have? The currently accepted answer by Anton Danilov says that [3, 2, 1] is not an ordered list:

?- List = [A, B, C], List = [3, 2, 1], ordered(List).
false.

but it also says that [3, 2, 1] is an instance of an ordered list:

?- List = [A, B, C], ordered(List), List = [3, 2, 1].
List = [3, 2, 1],
A = 3,
B = 2,
C = 1 ;
false.

Viewed logically, this is a contradiction. Viewed procedurally, it is fine, but also the @=< relationship between the variables in the list is meaningless. The comparison of the unbound variables does not say anything about the relationship of the list elements if they are bound to values at some point.

You can use constraints to exclude future unordered bindings:

:- use_module(library(clpfd)).

ordered([]).
ordered([_]).
ordered([X, Y | Xs]) :-
    X #=< Y,
    ordered([Y | Xs]).

This way you cannot bind the variables in the list to incorrect numbers later on:

?- List = [A, B, C], List = [3, 2, 1], ordered(List).
false.

?- List = [A, B, C], ordered(List), List = [3, 2, 1].
false.

But later correct ordered bindings are still allowed:

?- List = [A, B, C], ordered(List), List = [1, 2, 3].
List = [1, 2, 3],
A = 1,
B = 2,
C = 3 ;
false.

This may not be the best solution, but I believe it can give you some idea of how to do what you need. In SWI-Prolog, the predicate freeze(+Var,:Goal) delays the execution of Goal until Var is bound.

ordered([]).
ordered([_]).
ordered([X,Y|R]) :- 
   freeze( X, 
           freeze( Y, 
                   ( X @=< Y, 
                     ordered([Y|R]) ) ) ).

Here are some examples with finite lists:

?- ordered([1,2,3]).
true.

?- ordered([1,2,3,0]).
false.

?- ordered(L), L=[1,2,3].
L = [1, 2, 3] ;
false.

?- ordered(L), L=[1,2,3,0].
false.

For an infinite list, you will need to "take" its prefix:

take([]).
take([_|R]) :- take(R).

Here is an example with infinite list:

?- ordered(L), take(L).
L = [] ;
L = [_375396] ;
L = [_376366, _376372],
freeze(_376366, freeze(_376372,  (_376366@=<_376372, ordered([])))) ;
L = [_377472, _377478, _377484],
freeze(_377472, freeze(_377478,  (_377472@=<_377478, ordered([_377484])))) ;
L = [_378590, _378596, _378602, _378608],
freeze(_378590, freeze(_378596,  (_378590@=<_378596, ordered([_378602, _378608])))) ;
L = [_379720, _379726, _379732, _379738, _379744],
freeze(_379720, freeze(_379726,  (_379720@=<_379726, ordered([_379732, _379738, _379744]))))
Related