2

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.

Fjodor
  • 529
  • 1
  • 7
  • 19
  • 1
    `setof(X, Y^foo(X,Y), Xs)` see http://www.swi-prolog.org/pldoc/man?predicate=bagof/3 –  Oct 22 '14 at 09:03
  • What? I'm using setof inside my predicate as you can see above. – Fjodor Oct 22 '14 at 09:04
  • "setof(+Template, +Goal, -Set) Equivalent to bagof/3, but sorts the result using sort/2 to get a sorted list of alternatives without duplicates." –  Oct 22 '14 at 09:06
  • `bagof/3` and `setof/3` are a bit confusing, compared to `findall/3`. You can just as well use `findall/3` followed by a `sort/2`, if you cannot exactly understand the behavior of `setof/3`. `findall/3` also doesn't fail when there are no solutions, which might be, depending on the use case, the correct thing. See http://stackoverflow.com/questions/26297171/adding-integers-in-prolog for few examples. –  Oct 22 '14 at 09:10
  • A correct example would be for it to wait until setof has put all values into a list and then return the full list. – Fjodor Oct 22 '14 at 09:11

2 Answers2

3

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)|_]).
false
  • 10,264
  • 13
  • 101
  • 209
  • What I am interested in doing is to find the country with the biggest "length" which would be stored in the list. Therefore the Country variable is needed so that I somehow can determine that Country X has the biggest length with length Y. – Fjodor Oct 22 '14 at 09:45
  • @Fjodor: See above. Next time state this in your question ; and always describe what your relations describe. `anotherPredicate/2` leaves a lot open for guessing. – false Oct 22 '14 at 10:01
  • Okay, will do that next time. I tried your code but it just gave me false O.o – Fjodor Oct 22 '14 at 10:09
  • I changed my answer with a copy of what I have written when it manage to fail – Fjodor Oct 22 '14 at 10:26
  • Well, the very first predicate I wrote in this thread contains anotherPredicate and it works. – Fjodor Oct 22 '14 at 10:32
2

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].
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135