2009-11-20 12 views
0

Tout d'abord laissez-moi vous dire que cela fait partie d'un exercice de classe donné comme devoir. Mais, l'ensemble de la mission est beaucoup plus impliqué que le sujet de cette question. Donc ..Travailler avec des listes dans Prolog

Je cherche dans deux listes données à une prédication. Mon but est de comparer les éléments correspondants dans cette liste et de déterminer si le premier est plus grand. Si c'est le cas, je dois finalement retourner une somme de tous ces termes. Voici ce que j'ai jusqu'à présent:

isumrow([], [], Iresult) :- 
    Iresult is 0. 
isumrow([Hi1row | Ti1row], [Hi2row | Ti2row], Iresult) :- 
    if((Hi1row - Hi2row), IsumDiff, Hi1row), 
    NewIresult is IsumDiff + Iresult, 
    isumrow(Ti1row, Ti2row, NewIresult), 
    Iresult is NewIresult. 

if(Diff, Iresult, Entry) :- 
    Diff > 0,      

    Iresult is Entry. 

if(_, Iresult, _) :- 
    Iresult is 0. 

Pour une raison quelconque, je suis de déconner quelque part dans mes devoirs et je ne suis pas sûr où. Tous les indices seraient appréciés. Encore une fois, cela fait partie d'une mission beaucoup plus vaste que je travaille, mais je ne peux pas l'obtenir. Merci

+0

Lequel avez-vous besoin de calculer: somme (max (A [i], B [i]) pour i dans 1..len (A)) ou somme (max (A [i] -B [i], 0) pour i dans 1..len (A))? – liori

+0

(BTW, vous surutilisez 'is'. Vous avez besoin de' is' pour calculer la somme et la différence, ce n'est pas nécessaire pour les affectations simples – liori

+0

Je ne suis pas sûr de comprendre votre question Si j'ai deux listes, la liste 1 est [ 0,0,0,1] et la liste 2 est [0,0,3,0]. J'ai besoin de faire une recherche dans la liste jusqu'à ce que je trouve un élément correspondant dans la liste 1 qui est plus grand que celui de la liste 2. Dans ce cas, cela se produirait avec 1> 0. Prédicat "si" renvoie cette valeur qui est plus grande (1) qui est ajoutée à un total cumulé Ce total cumulé dont j'ai besoin est retourné à la fin –

Répondre

0

Je vais essayer d'introduire le moins de changements possible à votre code.

Une chose qui est définitivement fausse est l'endroit où vous essayez de calculer la différence. Prolog effectue des calculs arithmétiques uniquement avec l'opérateur is. Votre code:

if((Hi1row - Hi2row), IsumDiff, Hi1row), 

se contente de transmettre l'expression de la forme (X-Y) au prédicat if, et non pas le calculer. Plus tard à l'intérieur de if, vous ne calculez pas la différence, mais essayez de comparer l'expression à zéro ... qui échoue, car vous ne pouvez comparer les nombres qu'aux nombres, et non aux expressions - et Diff est assigné à une expression.

Il fonctionnerait si vous réécrivez la première clause de se comme suit (même si vous devriez également vous débarrasser de cette is ici):

if((X-Y), Iresult, Entry) :- 
    X > Y, 
    Iresult is Entry. 

De cette façon, votre if prédicat obtiendra X et Y de la expression pour pouvoir les comparer.

De même, vous devez éviter votre prédicat if pour obtenir deux réponses possibles. Votre deuxième clause if sera invoquée même lorsque X> Y: dans le processus de retour arrière. Le plus simple est de mettre ! à la fin de la première clause. Cela signifie: "Jusqu'à présent, j'accepte la première solution dans ce programme et je ne veux pas revenir d'ici pour trouver d'autres solutions". La clause sera modifiée:

if((X-Y), Iresult, Entry) :- 
    X > Y, 
    Iresult is Entry, 
    !. 

Mais ... ce qui est bon dans les petits programmes, et si vous avez besoin réellement faire marche arrière dans d'autres parties de votre programme, cela peut casser. Le moyen le plus propre serait de vérifier l'état correct dans les deux clauses. les récrire à:

if((X-Y), Iresult, Entry) :- 
    X > Y,           
    Iresult is Entry. 

if((X-Y), Iresult, _) :- 
    X =< Y, 
    Iresult is 0. 

Ensuite, vous êtes sûr que si X> Y, la deuxième clause échouera.

Après ces modifications, votre code devrait fonctionner ... Veuillez le signaler si ce n'est pas le cas. Ce ne sera toujours pas très prolog-ish cependant; c'est un peu trop verbeux.


Edit:

Ok, je l'écrire d'une manière simple:

sum_if_bigger([], [], 0). 
sum_if_bigger([A|L1], [B|L2], Result) :- 
     sum_if_bigger(L1, L2, Partial), 
     Result is Partial + max(0, A-B). 

...ou d'une manière récursive:

sum_if_bigger_tr(L1, L2, R) :- 
     sum_if_bigger_tr(L1, L2, 0, R). 
sum_if_bigger_tr([], [], R, R). 
sum_if_bigger_tr([A|L1], [B|L2], Partial, Result) :- 
     NewPartial is Partial + max(0, A-B), 
     sum_if_bigger_tr(L1, L2, NewPartial, Result). 
+0

Je comprends vos révisions et les ai implémentées mais je n'obtiens toujours pas les résultats souhaités. Je n'ai pas l'intention d'utiliser ce code que j'ai écrit, donc s'il y a des façons meilleures ou plus propres de mettre en œuvre ce processus, je suis ouvert aux idées. Fondamentalement, j'ai 2 listes de listes que j'ai besoin de comparer. Comme je l'ai dit plus tôt, si l'élément correspondant dans la liste 1 est plus grand que je vais ajouter cet élément au total cumulé. Ce total est ce dont j'ai besoin pour le reste de mon programme. Encore une fois, je ne vous demande pas de résoudre mon problème, mais je ne pense pas que je suis en train de saisir le concept de prologue à la bonne façon. –

+0

Pourriez-vous peut-être fournir un autre moyen de résoudre ce problème ou de montrer quelques exemples? Merci –

+0

BTW, vous pouvez essayer de travailler comment le code (à la fois votre et le mien) fonctionne en utilisant 'trace/0'. Entrez simplement 'trace.' dans l'invite de swipl, lancez une requête et appuyez sur Entrée pour procéder étape par étape. Utilisez 'notrace.' pour arrêter le traçage. – liori

1
isumrow([], [], Iresult) :- 
    Iresult is 0. 

isumrow([Hi1row | Ti1row], [Hi2row | Ti2row], Iresult) :- 
    if((Hi1row - Hi2row), IsumDiff, Hi1row),    
    NewIresult is IsumDiff + Iresult, 
    isumrow(Ti1row, Ti2row, NewIresult), 
    Iresult is NewIresult. 

if(Diff, Iresult, Entry) :- 
    Diff > 0,            
    Iresult is Entry. 

if(_, Iresult, _) :- 
    Iresult is 0.