0

I'm having some problems with a simple program in Prolog. I have two different groups, and I would like to attach an element of one group to another, without directly modifying the facts (eg: Toronto = USA).

country(usa,    northamerica).
country(canada, northamerica).

city​​(chicago,    usa).
city​​(newyork,    usa).
city​​(losangeles, usa).
city​​(dallas,     usa).
city​​(miami,      usa).
city​​(lasvegas,   usa).
city​​(seattle,    usa).

city​​(toronto,    canada).
city​​(vancouver,  canada).
city​​(ottawa,     canada).
city​​(richmond,   canada).
city​​(winnipeg,   canada).
city​​(edmundston, canada).
city​​(hamilton,   canada).

trip(john, usa).
trip(jack, canada).

In this example, John traveled to seven cities in the USA, while Jack traveled to others seven cities in Canada.

However, John recently traveled to Toronto. I would like to reach the following result:

? - trip_plus(X, john).

X = chicago;
X = newyork;
X = losangeles;
X = dallas;
X = miami;
X = lasvegas;
X = seattle;
X = toronto;

?- yes

I tried many times unsuccessfully to get the result above. The closest I could get was using the following:

country(C).
city(Y).
trip(T).
trip_plus(X, T) :- city(Y, C), trip(T, C).

What am I doing wrong?

Thanks mates.

2 Answers2

1

I am not sure if I understood you properly: you want to create a predicate that lists all the cities that someone have visited? I will split my solution to three cases.

First, we will list all the direct "to city trips", e.g. trip(john, toronto), trip(john, newyork).

trip_plus(City, Who) :-
  % we grab all the trip(*, *) pairs
  trip(Who, City),
  % and we leave only cities
  city(City, _).

Then we want to list all cities in the "country trips", e.g. trip(john, usa):

trip_plus(City, Who) :-
  % again, we grab all the trip(*, *) pairs
  trip(Who, Country),
  % and we list all cities in given country (if it is a country)
  city(City, Country).

And at the end we want to list all cities in the "continent trips", e.g. trip(jack, northamerica):

trip_plus(City, Who) :-
  % the same thing
  trip(Who, Continent),
  % we list all countries on the continent
  country(Country, Continent),
  % and we list all cities in given country 
  city(City, Country).

The whole predicate looks like that:

trip_plus(City, Who) :-
  trip(Who, City),
  city(City, _).
trip_plus(City, Who) :-
  trip(Who, Country),
  city(City, Country).
trip_plus(City, Who) :-
  trip(Who, Continent),
  country(Country, Continent),
  city(City, Country).

So for your world database and those trips:

trip(john, usa).
trip(jack, canada).
trip(john, toronto).

we get:

?- trip_plus(X, john).
X = toronto ;
X = chicago ;
X = newyork ;
X = losangeles ;
X = dallas ;
X = miami ;
X = lasvegas ;
X = seattle ;
false.

You may notice that toronto is first while the entry trip(john, toronto) is last in the database. It is because we first look for "to city" trips. If the order does matter to you, the predicate may be written like that:

trip_plus(City, Who) :-
  trip(Who, Where),
  (
  city(Where, _), City = Where;
  city(City, Where);
  country(Country, Where), city(City, Country)
  ).

However I personally find it less obvious.

Pan Hania
  • 468
  • 4
  • 11
  • Thanks for your reply mate. I checked your both suggestions in SWI-Prolog Portable and it worked, although the other city (Toronto) appeared twice in the query search. In gprolog (for windows), i have no 'USA' in header like in SWI-and only the cities listed in USA, excluding toronto. Link: http://pastebin.com/vhF8NGbJ Thanks. – Allan Davidson Jul 08 '12 at 00:02
  • Can you attach the *.pl file that is being loaded to test? – Pan Hania Jul 09 '12 at 20:29
0

Well, you are not adding "John traveled to toronto" to the fact list, hence it will never appear. You could modify your code as follows:

%This is not needed => country(C). 

city(toronto). %here whatever city john visited
trip(john). %the person's name
trip_plus(X, T) :- trip(T,C), city(X,C) | trip(T) , city(X).
jonsca
  • 10,218
  • 26
  • 54
  • 62
Nullbeans
  • 309
  • 1
  • 8