1
votes

I'm new to prolog, and I really don't understand how things really work.

Giving the following knowledge base, from a simplified social network:

% user(nickname,email,city,friends_list)
user(nick0,mail0,lisbon,[nick1,nick8]).
user(nick1,mail1,lisbon,[nick0,nick3, nick5, nick9]).
user(nick2,mail2,london,[nick5,nick7,nick8]).
user(nick3,mail3,madrid,[nick1,nick4]).
user(nick4,mail4,paris,[nick1, nick3, nick2, nick5, nick6]).
user(nick5,mail5,madrid,[nick1, nick4, nick2]).
user(nick6,mail6,lisbon,[nick3,nick2]).
user(nick7,mail7,berlin,[nick3, nick5]).
user(nick8,mail8,berlin,[nick3, nick5, nick7]).
user(nick9,mail9,london,[nick1, nick4]).

I need a predicate places(NU,LC) that generates a list of citys (LC) with the citys where the number of users is greater or equal than (NU).

Example:

places(0,LC).

LC = [(lisbon,3), (london,2), (madrid,2), (paris,1), (berlin,2)]

I have the following code, and it doesn't work, I'd appreciate it if you guys could help me:

places(NU,LC):-
findall(X,user(_,_,X,_),List),
findall(Z,(user(_,_,Z,_),member(Z,List), Z>=NU),LC).

It may be a simple problem, but I'm still learning prolog.

1

1 Answers

1
votes

Of course, the answer will depend on what Prolog system you're using, because libraries could be available solving the query in single call. To stick with ISO predicates (well, apart member/2):

places(NU, LC) :-
    setof(City, User^Mail^Friends^user(User,Mail,City,Friends), Cities),
    findall((City, Count),
        (member(City, Cities),
         findall(_, user(_,_,City,_), L),
         length(L, Count),
         Count >= NU), LC).