Fjodor
Fjodor

Reputation: 539

Setof returning list every time, prolog

I am using a predicate that looks like this:

predicate(Country, X):-
    setof(Length, anotherPredicate(Country,Length), X).

My problem here is that my code returns the list X for every value. What I want is to return a big list containing all the numbers because right now I get the answer:

Country = adsfsadf;
X = [123];
Country = asfdsaf;
X = [312];

So instead of small lists every time I want a big list containing it all.

EDIT for comment ----------

predicate(Country, Length) :-
   setof(p(ML,C,L),
      ( anotherPredicate(C, L), ML is -L ),
      [p(_,Country, Length)|_]).

This is what I wrote and it gives me false instantly.

Upvotes: 2

Views: 4500

Answers (2)

false
false

Reputation: 10122

Currently you get one list for each solution of Country. This is so, because setof/3 identifies all free variables and produces a list for each different instantiation of these variables.

But what you are asking is inconsistent. One the one hand you want to have only a single list. That is easy to provide, provided you can build the set of the solutions easily.

 setof(Length, Country^anotherPredicate(Country,Length), X).

On the other hand you still want that Country variable to be present as the first argument of predicate/2! This does not make any sense. No more than to insist that a local variable be present in an outer context. Unfortunately, Prolog does not detect such errors directly. For with

predicate(Country, X):-
    setof(Length, Country^anotherPredicate(Country,Length), X).

?- predicate(C, L).
   L = [length_of_1, length_of_2].
?- C = c1, predicate(C, L).
   C = c1, L = [length_of_1].

That is, by specializing the goal (by adding C = c1), a different L is found.

There is one caveat, however: What should be the result, if there are two countries with identical length, say 23? Do you want a single element [23] or two [23,23]? This is not clear from your description.

Should you want two, you will have to determine first:

setof(Country-Length, anotherPredicate(Country, Length), CL),
keys_values(CL, Lengths),
...

Edit: in response to your comment:

biggestcountry_val(Country, Length) :-
   setof(p(ML,C,L),
      ( anotherPredicate(C, L), ML is -L ),
      [p(_,Country, Length)|_]).

Upvotes: 3

Nicholas Carey
Nicholas Carey

Reputation: 74317

Without some sample data and expected/desired results, it's a bit hard to tell what you need. However...Examining the state of the argument in your predicate might give you what you're looking for.

For example, given this data:

foo( albania ,  1 ) .
foo( albania ,  2 ) .
foo( albania ,  3 ) .
foo( albania ,  4 ) .
foo( albania ,  5 ) .
foo( albania ,  6 ) .
foo( iceland ,  4 ) .
foo( iceland ,  5 ) .
foo( iceland ,  6 ) .
foo( iceland ,  7 ) .
foo( iceland ,  8 ) .
foo( iceland ,  9 ) .
foo( france  ,  7 ) .
foo( france  ,  8 ) .
foo( france  ,  9 ) .
foo( france  , 10 ) .
foo( france  , 11 ) .
foo( france  , 12 ) .

Your initial cut at things shown in your question

predicate(Country, X):-
  setof(Length, foo(Country,Length), X).

returns these multiple results when invoked with Country being an unbound variable:

?- predicate(Country,X).
Country = albania , X = [1, 2, 3, 4, 5, 6] ;
Country = france  , X = [7, 8, 9, 10, 11, 12] ;
Country = iceland , X = [4, 5, 6, 7, 8, 9] .

And this single result if invoked with Country being bound to a valid country, iceland in this case:

?- predicate(iceland,X).
X = [4, 5, 6, 7, 8, 9].

If you do something like this, however,

predicate( C , Xs ) :- var(C)    , setof( X , C^foo(C,X) , Xs ) .
predicate( C , Xs ) :- nonvar(C) , setof( X ,   foo(C,X) , Xs ) .

You'll get this one solution when the argument is unbound:

?- try_this(C,Xs).
Xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] ;
false.

You'll notice that C remains unbound.

And you'll get this this one result when the argument is bound:

?- try_this(iceland,Xs).
Xs = [4, 5, 6, 7, 8, 9].

Upvotes: 2

Related Questions