2009-11-22 5 views
1

J'ai une base de données constituée des règles suivantes;Question sur la liste Prolog

speaks(fred [german, english, dutch]). 
speaks(mary [spanish, arabic, dutch]). 
speaks(jim [norwegian, italian, english]). 
speaks(sam [polish, swedish, danish]). 

etc

Dans le cadre d'un programme beaucoup plus vaste, comment pourrais-je savoir 3 personnes qui parlent la même langue?

Jen

+5

devrait-il pas être 'parle (fred, [allemand , anglais, néerlandais]). '(remarquez la virgule supplémentaire)? Aussi: est ce devoir? Si oui, merci de l'indiquer comme devoirs. – Franz

+0

Il a une odeur de travail. – nedned

Répondre

0

Il a été un certain temps, donc il peut y avoir quelques problèmes de syntaxe, mais j'espère que vous avez l'idée ...

% Find out whether an element is contained in a list 
in_list(X,[X|_]). 
in_list(X,[First|Rest]) :- in_list(X,Rest). 

% Find out 3 people who speak the same language 
findspeakers(Language, X1, X2, X3) :- speaks(X1, L1), speaks(X2, L2), speaks(X3, L3), in_list(Language, L1), in_list(Language, L2), in_list(Language, L3). 

solution assez simple en utilisant des opérateurs de liste (je ne l'ai pas se rappeler s'il y avait une règle intégrée pour découvrir si une variable est contenue dans une liste, ainsi je l'ai réécrit).

Vous pouvez trouver des groupes de trois personnes parlant anglais avec la commande suivante:

findspeakers('English', X1, X2, X3). 

Vous pouvez trouver tous les groupes de trois personnes parlant une langue commune avec la commande suivante:

findspeakers(Language, X1, X2, X3). 

NOTE: Ces commandes vous donneront toutes les combinaisons possibles de groupes de trois personnes, donc si vous avez quatre personnes qui parlent anglais, la première commande vous donnera quatre ensembles de résultats.

+0

Je pourrais juste être fatigué, mais je pense qu'il donnera 64 jeux de résultats dans ce cas, car il génère des permutations avec répétition permise, pas des combinaisons avec la répétition interdite. – bcat

+0

En outre, il existe en effet un prédicat qui fait ce que fait votre 'in_list/2':' member/2'. Je ne pense pas que ce soit dans la norme ISO, mais il devrait avoir un support quasi-universel en tant qu'extension. – bcat

+0

Ah, cool. Merci pour les commentaires. Surtout le premier est très intéressant - je ne le savais pas ... – Franz

3

Comme il est, Franz' solution ne fonctionnera pas: il renvoie des triplets de prople qui parlent la même langue, mais ces triplets peuvent contenir des doublons. Ainsi, il faudrait toujours recourir, par exemple, à sort/2 et length/2 pour trouver la réponse à la question initiale:

?- findspeakers(Language, X1, X2, X3), sort([X1, X2, X3], Y), length(Y, 3). 
false. 

(La réponse est pas, il n'y a pas trois personnes parlant la même langue.) Quoi qu'il en soit, je pense une solution plus élégante existe:

spoken(L, S) :- 
    speaks(S, LL), member(L, LL). 

same_language(N, L, SS) :- 
    bagof(S, spoken(L, S), SS), length(SS, N). 

Le prédicat spoken/2 utilise member/2 et réussit si la langue est parlée par L personne S. same_language/3 réussit si la liste SS contient N personnes distinctes, toutes parlant la langue L. Ce prédicat utilise bagof/3; Si la définition du prédicat speak/2 contient des données en double, vous devez utiliser setof/3 à la place.

Notez que ce bien le problème se généralise: nous pouvons maintenant répondre à la question pour touten, non seulement 3. Démonstration:

?- same_language(3, L, SS). 
false. 

?- same_language(2, L, SS). 
L = dutch, 
SS = [fred, mary] ; 
L = english, 
SS = [fred, jim] ; 
false. 
+0

Wow. très bonne réponse. La vôtre dépasse de beaucoup mes connaissances Prolog;) – Franz

+0

Ouais, moi aussi. J'ai eu l'intention d'apprendre comment 'bagof' et' setof' fonctionnent, et c'est un bel exemple à partir duquel puiser. – bcat