1

I have a predicate which purpose is to print out which country that has the biggest area(one with biggest border = biggest area). This is how my predicate looks like:

/* If I write get_country(X, 'Europe'). then all the countries in Europe 
that isn't bordering a sea gets printed out. 
However as you can see I am creating a list 
with all of the countries and then I want to
take the largest country from all of these 
and print that one out. But instead 
all of the countries gets printed out 
with their length, ex: X = hungary ; 359 (length) ...  */
get_country(Country, Region):-
    encompasses(Country,Region,_),
    not(geo_sea(_,Country,_)),
    setof(Length, country_circumference(Country,Length), Cs),
    largest(Cs, X),
    write(X).

The predicates used within that predicate follows:

country_circumference(Country, X):-
    setof(Length, get_border_length(Country, Length), Cs),
    sum(Cs, X).

largest([X],X).
largest([X|Xs],R) :-
    largest(Xs,Y),
    R is max(X,Y).

Can anyone tell me what I am doing wrong here? How do I simply get all of my countries into the list and then traverse through the list to find the one with the biggest border instead of just printing them out one after one as I put them into the list? Thanks in advance.

false
  • 10,264
  • 13
  • 101
  • 209
Fjodor
  • 529
  • 1
  • 7
  • 19
  • 1
    The values in `Cs` are already sorted in ascending order. So you just need to take the last - or make the value negative and take the first. – false Mar 03 '15 at 09:52
  • Okay, any idea on how I would apply that to the get_country predicate? – Fjodor Mar 03 '15 at 10:03

1 Answers1

2

Prolog defines a natural order of terms. For example, the following are true:

foo(3, z) @< foo(10, x)
bar(2, 9) @< foo(3, 1)

Note the use of the term comparison operator @< versus the numeric comparison <. The predicate, setof/3, will do term comparison.

If you want to find the country that has the longest border, then you can do so by taking advantage of the term comparison and collect like terms in setof/3 that have the item you want to sort by as the first argument. In this case, we'd want the circumference first. In addition, if I'm understanding the intended meaning of your get_country predicate correctly, you need to include the queries that define the countries you want to consider as part of the query in the setof/3:

get_country(Country, Region):-
    setof(L-C-R, X^Y^Z^( encompasses(C, R, X),
                         \+ geo_sea(Y, C, Z),
                         country_circumference(C, L) ), Cs),
    reverse(Cs, HighToLowAreas),
    member(_-Country-Region, HighToLowAreas), !.

The member/2 at the end of the predicate clause will find the first element in the list HighToLowAreas that matches _-Country-Region, which will be the first element if Country and Region are initially uninstantiated.

The existential quantifiers X^Y^Z^ are needed to exclude these from being selectors in the query. Using _ won't do that in the context of setof/3. Here, we're using the term form, -(-(X,Y),Z) since it's conveniently written, X-Y-Z. But you could just as well use, foo(X, Y, Z) here. The reverse/2 puts the list Cs in descending order, and we just pick off the Country and Region from the head of that list with, [_-Country-Region].

lurker
  • 56,987
  • 9
  • 69
  • 103
  • Hello and sorry for not answering. This worked but only when I typed get_country(X, 'Europe'). Answer was X = Kazakstan. But whenever I type any other continent, ex get_country(X, 'Asia'), it just gives me false :s I understand this is grasping for straws but could you know what the problem is? – Fjodor Apr 28 '15 at 09:23
  • @Fjodor my answer assumes that your other predicates perform as you expect. Did you test `country_circumference` independently, for example, to confirm it does what you want? And is `encompasses` querying facts, or is it also a predicate? – lurker Apr 28 '15 at 11:08
  • Yes, country_circumference has been tested and works. It lists all countries and their border circumference. And encompasses is only fact, example: encompasses(hong_kong, 'Asia',100). – Fjodor Apr 28 '15 at 11:14
  • Okay I tested changing the circumference of kazakstan. Now when I typed get_country(X, 'Europe') I get false as answer but if I write get_country(X, 'Asia') I get Mongolia as answer. So now Mongolia is the country with biggest circumference. The problem with your answer is that it only works if I had one continent :D But if I type get_country(X, 'Asia') I want the country with biggest circumference in Asia etc. But right now it checks if the country with biggest circumference is located in Asia which is wrong... do you know how to fix this problem? – Fjodor Apr 28 '15 at 11:29
  • @Fjodor thanks for explaining. My original solution would find the largest overall, so querying a specific one that was not the largest would yield "false". I updated the answer to behave the way you asked, so see if that works for you. – lurker Apr 28 '15 at 13:29