2
votes

Existe-t-il un moyen de résumer uniquement les entiers dans une liste de paires contenant une lettre et un entier dans Prolog?

J'ai du mal à trouver comment trouver la somme des nombres entiers qui sont dans une liste de paires comme ceci:

sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total),
write('Sum = '), write(Total).

J'ai essayé quelque chose comme ça, car cela rappelle une fonction somme régulière:

sum([], 0).
sum([[_,Head]|[_,Tail]], Sum) :-
    sum([_,Tail], Sum2),
    Sum is Head+Sum2.

Avec l'appel étant:

[[a, 1], [b, 2], [c, 3], [d, 4]]

Mais cela ne fonctionne pas. Il affiche false, alors qu'il doit afficher la somme, qui serait de 10 ici.


2 commentaires

sum ([[_, Head] | [_, Tail]], Sum) -> cela indique qu'il ne correspond qu'à une liste avec deux éléments, et rien d'autre. La section de queue entière doit porter un seul nom. Cette question a été posée hier et a une réponse ici: stackoverflow.com/questions/55776612/... si une réponse est ce que vous recherchez.


Les répondants ont raison: c'est une bonne opportunité d'apprentissage. Mais la réponse simple est: vous avez dit [_, Tail] quand vous vouliez dire Tail. Le reste de la liste n'est pas 2 éléments à appeler _ et Tail, mais 3 éléments, mieux appelés collectivement Tail.


3 Réponses :


1
votes

Je pense qu'il pourrait être utile de diviser cela en deux tâches:

  1. créer une nouvelle liste du deuxième élément de chaque sous-liste; et
  2. résume cette liste.

Cela facilite la résolution des deux problèmes, et en plus vous avez maintenant deux prédicats supplémentaires qui peuvent être utilisés à d'autres fins.

Nous pouvons obtenir une liste du deuxième élément de les sous-listes avec:

?- item2list([[a, 1], [b, 2], [c, 3], [d, 4]], L).
L = [1, 2, 3, 4].

ou nous pouvons utiliser maplist / 3 [swi-doc] et nth1 / 3 [swi-doc] :

XXX

ou nous pouvons écrire item2list en termes de findall / 3 [swi-doc] et membre / 2 [swi-doc] : p >

item2list(L1, L2) :-
    findall(X, member([_,X|_], L1), L2).

bien qu'ici le prédicat ne soit pas bidirectionnel.

Par exemple:

XXX

Je laisse résumer cette liste comme un exercice.


2 commentaires

findall / 3 + member / 2 vous donnera une implémentation nettement plus rapide pour votre prédicat item2list / 2


Mais findall / 3 dérangerait les contraintes. La solution maplist / 3 n'a pas ce problème.



1
votes

Dans votre tentative de définir le prédicat sum / 2 , vous ne gérez pas correctement les listes de listes. Essayez:

| ?- sum([[a, 1], [b, 2], [c, 3], [d, 4]], Sum).

Sum = 10
yes

Cette version utilise un accumulateur pour activer une définition récursive de queue. Exemple d'appel:

sum(Lists, Sum) :-
    sum(Lists, 0, Sum).

sum([], Sum, Sum).
sum([[_,N]| Lists], Sum0, Sum) :-
    Sum1 is Sum0 + N,
    sum(Lists, Sum1, Sum).


0 commentaires

1
votes

Chaque fois qu'un objectif échoue et que vous espérez réussir, voyez-le comme une occasion d ' apprendre (forme abrégée de la logique gagner = gagner de la logique). Après tout, c'est Prolog qui était censé signifier Programmation dans Logic . Alors, où est la logique de votre programme?

Pour le moment, votre programme échoue, mais vous vous attendiez à ce qu'il réussisse. Où est le coupable? généralisons votre programme de sorte que le programme résultant échoue toujours, mais qu'il soit beaucoup plus petit. Il existe deux manières simples de généraliser un programme:

  • supprimer des objectifs (en ajoutant un préfixe *)

  • supprimer les termes (en remplaçant terme par _/*term*/

Nous pouvons le faire assez aveuglément. Pas besoin de comprendre votre programme. Vérifiez simplement que l'objectif échoue toujours. Voici ce que j'ai trouvé lors de mon premier essai:

sum([], _/*0*/).
sum([_/*[_,Head]*/|[_,Tail|_/*[]*/]], Sum) :-
    sum([_,Tail], Sum2),
    * Sum is Head+Sum2.

?- Os = [_|_], sum(Os, Total).
false.

Un problème doit être dans la partie visible restante. Trop difficile à comprendre? Laissez Prolog vous l'expliquer en interrogeant la requête la plus générale :

?- sum(Os, Total).
   Os = [], Total = 0
;  false.

Ainsi, seules deux longueurs de listes sont possibles: la liste vide et une liste avec trois éléments. Notez que nous avons actuellement une version généralisée du prédicat. Il n'y a donc aucune garantie que nous trouverons des solutions pour les deux longueurs. Cependant, nous pouvons être sûrs à 100% que pour toutes les autres longueurs, il n'y aura pas de solution.

Revenons au programme d'origine et posons la requête la plus générale:

| ?- sum(Xs, Sum).
   Xs = []
;  Xs = [_A,_B,_C].


0 commentaires