2010-01-29 3 views
2

J'ai décidé d'étudier la programmation logique et j'ai trébuché sur un problème. Il est programmé dans SWI Prolog.Retour d'une valeur après une récursion dans Prolog

test(A, B, N):- 
nonvar(B), 
B = final, 
true. 

test(A, B, N):- 
N > 2, 
test(A, final, N). 

test(A, B, N):- 
N1 is N + 1, 
test(N1, B, N1). 

C'est juste un échantillon sans utilisation réelle, sauf que ça me rend fou.

Le problème est que lorsque le code atteint true, il commence à repérer et répond "vrai". Mais j'ai besoin de "retourner" la valeur A. Comment je fais ça?

+0

Une question rapide: que voulez-vous réellement que le code fasse? – rvirding

Répondre

2

Je n'ai pas mon compilateur Prolog ici, mais avez-vous essayé quelque chose le long des lignes de:

test(A, B, N, A):- 
nonvar(B), 
B = final, 
true. 

test(A, B, N, Result):- 
N > 2, 
test(A, final, N, Result). 

test(A, B, N, Result):- 
N1 is N + 1, 
test(N1, B, N1, Result). 
+0

J'ai besoin de renvoyer une valeur de la variable A qui est 3 quand vrai est appelé. Comment puis-je y parvenir? Votre code ci-dessus ne le fait pas. Merci, Petr – petr

+0

Que diriez-vous comme ça alors? (Je vais faire fonctionner ce code dans 2h fois quand je serai de retour à la maison) – rui

+1

Le code ci-dessus semble bien fonctionner, je l'ai juste essayé. Pouvez-vous me donner un exemple d'entrée/sortie d'échantillon? – rui

8

A est pas unifié avec quoi que ce soit dans le corps de vos règles. La façon dont prolog fonctionne est via l'unification des termes. Vous ne pouvez pas "retourner" A comme dans les langages procéduraux en tant que tels. Par exemple, que voulez-vous que la valeur de A soit lorsque la récursion arrive à son terme? Je n'ai aucune idée de ce que fait votre code, alors laissez-moi utiliser un exemple.

accumulate([], A, A). 
    accumulate([H|T], A, N) :- A1 is A + H, accumulate(T, A1, N). 

    sum([], 0). 
    sum(L, N) :- accumulate(L,0,N). 

Voici une procédure de somme qui résumera les valeurs dans une liste et « retour N », la somme des valeurs de la liste. Pour appeler cette procédure, vous pouvez le faire:

sum([2, 3, 4], N). 

Et Prolog répondra:

N = 9 

Avis la procédure accumulate utilise A comme un accumulateur comme la récursion se poursuit. Autrement dit, A garde la somme courante, tandis que N est la réponse finale qu'elle renvoie. Pendant la récurrence, N n'est pas unifié avec une valeur réelle.

Dans la dernière étape de la récursion, qui est, lorsque la liste est vide, la valeur de A est unifiée avec N, en effet le retour N.


Laissez-nous faire une trace.

[trace] 4 ?- test(A, B, 0). 
    Call: (7) test(_G417, _G418, 0) ? creep//A unifies with _G417 (internal variable name), B with _G418 and N with 0. 
    Call: (8) nonvar(_G418) ? creep 
    Fail: (8) nonvar(_G418) ? creep 
    Redo: (7) test(_G417, _G418, 0) ? creep//Unifies with clause 2, 
^ Call: (8) 0>2 ? creep 
^ Fail: (8) 0>2 ? creep 
    Redo: (7) test(_G417, _G418, 0) ? creep //Unifies with clause 3 
^ Call: (8) _L183 is 0+1 ? creep 
^ Exit: (8) 1 is 0+1 ? creep 
    Call: (8) test(1, _G418, 1) ? creep //recursive call, unifies with 
    Call: (9) nonvar(_G418) ? creep 
    Fail: (9) nonvar(_G418) ? creep 
    Redo: (8) test(1, _G418, 1) ? creep 
^ Call: (9) 1>2 ? creep 
^ Fail: (9) 1>2 ? creep 
    Redo: (8) test(1, _G418, 1) ? creep 
^ Call: (9) _L195 is 1+1 ? creep 
^ Exit: (9) 2 is 1+1 ? creep 
    Call: (9) test(2, _G418, 2) ? creep 
    Call: (10) nonvar(_G418) ? creep 
    Fail: (10) nonvar(_G418) ? creep 
    Redo: (9) test(2, _G418, 2) ? creep 
^ Call: (10) 2>2 ? creep 
^ Fail: (10) 2>2 ? creep 
    Redo: (9) test(2, _G418, 2) ? creep 
^ Call: (10) _L207 is 2+1 ? creep 
^ Exit: (10) 3 is 2+1 ? creep 
    Call: (10) test(3, _G418, 3) ? creep 
    Call: (11) nonvar(_G418) ? creep 
    Fail: (11) nonvar(_G418) ? creep 
    Redo: (10) test(3, _G418, 3) ? creep 
^ Call: (11) 3>2 ? creep 
^ Exit: (11) 3>2 ? creep 
    Call: (11) test(3, final, 3) ? creep 
    Call: (12) nonvar(final) ? creep 
    Exit: (12) nonvar(final) ? creep 
    Call: (12) final=final ? creep 
    Exit: (12) final=final ? creep 
    Call: (12) true ? creep 
    Exit: (12) true ? creep 
    Exit: (11) test(3, final, 3) ? creep 
    Exit: (10) test(3, _G418, 3) ? creep 
    Exit: (9) test(2, _G418, 2) ? creep 
    Exit: (8) test(1, _G418, 1) ? creep 
    Exit: (7) test(_G417, _G418, 0) ? creep 

Maintenant, notez le point dans la trace où j'ai marqué //A unifies with _G417 (internal variable name), B with _G418 and N with 0.. À ce stade, A est votre variable externe et _G417 est votre A. interne. Si cet appel réussit, il finira par ne signaler que les valeurs des variables externes. En interne _G417 n'est jamais unifié avec autre chose. Je pense que le problème est de comprendre comment fonctionne le modèle d'unification de Prolog.

+0

Je crois que mon problème est un peu différent. Regardez mon échantillon: Je demande le test Prolog (A, B, 0). Prolog passe par les prédicats et compte N1 jusqu'à ce que N1 soit> 2. Lorsque cela se produit, les appels de prédicats testent récursivement (A, final, N). Donc, à cette étape A est 3, N est 3 et B est final. nonvar (B) réussit, B = final réussit si vrai est appelé. À ce stade, Prolog fait un retour en arrière et revient à la fin. Mais j'ai demandé à propos de A et B, pas vrai. J'ai besoin de la valeur A retournée par Prolog. – petr

+0

Je ne sais pas comment forcer le prédicat à se terminer au point où la valeur A est affectée. J'ai essayé des coupes mais pas de succès. – petr

+0

@petr Voir mes modifications ci-dessus. –