1
votes

I have simplified my code down to;

findall(T,(T > 0, T < 50),List).

Why would this fail with given error.

2
Because T never gets a value. There are easier ways to get a list of ints.Tomas By

2 Answers

3
votes

Here is your code simplified even further:

?- T > 0.
ERROR: >/2: Arguments are not sufficiently instantiated

The "classical" comparison operations like < and > need all their arguments to be fully instantiated to ground terms; in particular, they cannot be unbound variables. (The same is true for the term on the right-hand-side of the is/2 operator.)

You can not use these operators as generators. Here is one illustration of a possible reason why:

?- T = 1, T > 0.
T = 1.

?- T = 0.1, T > 0.
T = 0.1.

?- T = 0.01, T > 0.
T = 0.01.

?- T = 0.001, T > 0.
T = 0.001.

The > operator works for several different types of numbers, including floating-point numbers. If we wanted it to be a logically reasonable generator, it would have to be able to generate all the floating-point numbers it accepts in the example above. That would almost certainly not be what you want.

There are a few ways to get what you want. As you presumably want integers only, you can use the between/3 predicate provided by many Prolog systems (including SWI):

?- between(1, 49, T).
T = 1 ;
T = 2 ;
T = 3 ;
T = 4 .

?- findall(T, between(1, 49, T), List).
List = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].

Another possibility is to use a constraint programming library. Here is one example session with SWI-Prolog's clpfd library:

?- use_module(library(clpfd)).
true.

?- T #> 0, T #< 50.
T in 1..49.

Note that here, using #> and #< from the clpfd library instead of < and >, we can actually specify these constraints even on an unbound variable. These constraints are remembered for later use, but they do not enumerate actual values for T. You can use them in arithmetic and comparisons, and the system will sometimes reason things out correctly even though it doesn't enumerate concrete values! For example:

?- T #> 0, T #< 50, X #= T - 50, X #> 50.
false.

To get actual values, you call a specific predicate that enumerates them:

?- T #> 0, T #< 50, indomain(T).
T = 1 ;
T = 2 ;
T = 3 ;
T = 4 .

All this gives another possible solution for your problem:

?- findall(T, (T #> 0, T #< 50, indomain(T)), List).
List = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
0
votes

If you want filtering, how about writing like this:

bagof(T,(member(T,[0,-4,34,15,76,100,200,43,21]),T>0,T<50),List).

List will be [34,15,43,21]. (though I didn't test)

If you just want to enumurate 1 to 49, ignore this answer(others have already answered)