2010-10-25 24 views
0

Ok, voici l'affaire:Prolog - valeur de retour de cas de base

  • J'ai deux piles de chemises
  • Je veux prendre une chemise au hasard de chaque pile et les mettre dans une nouvelle pile
  • obtenez alors la nouvelle pile sur

Et voici le code:

mix([],[],_). 
mix(P1,P2, Pile):- 
    takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one 
    append(Pile,Taken1,New),  append(New,Taken2,NewPile), #Put both of them 
    mix(Remain1,Remain2,NewPile). 

C'est ce que le résultat ressemble à:

1 ?- mix([a,b],[c,d],NewPile). 
NewPile = [] . 

Je veux que ça ressemble à:

1 ?- mix([a,b],[c,d],NewPile). 
NewPile = [b, d, a, c] . 

Ou quel que soit le résultat. J'ai vérifié par le débogueur graphique et découvert que lorsque le dernier mélange se produit, les liaisons sont:

P1 = Taken1 = [b] 
P2 = Taken2 = [c] 
Pile   = [a, d] 
Rem1 = Rem2 = [] 
New   = [a, d, b] 
NewPile  = [a, d, b, c] #<--- Interresting 

Ainsi, la valeur recherchée est NewPile lorsque le dernier:

mix([],[],_). 

arrive. Après cela, il s'effondre comme un château de cartes.

La question est:

mix([],[],_). 

Je voudrais revenir à la _ valeur du cas de base, cette règle mélange est effectivement utilisé à partir d'une instance supérieure où je vous envoie en deux piles et récupérez la nouvelle pile.

Mise à jour:
Pour clarifier certains commentaires au sujet de la takeshirt règle, la voici:

takeshirt(_,0,[],_). 
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0, 
    length(List,Len), 
    Index is random(Len) + 1, 
    removeshirt_at(Element,List,Index,Remain), 
    Number1 is Number - 1, 
    takeshirt(Remain,Number1,Taken,Remain). 

Répondre

2

Tenir compte les modifications suivantes à votre code:

mix([], [], []) :- !. 
mix(P1, P2, Pile) :- 
    takeshirt(P1, 1, Taken1, Rem1), 
    takeshirt(P2, 1, Taken2, Rem2), 
    append(Taken1, Taken2, Pile0), 
    mix(Rem1, Rem2, Pile1), 
    append(Pile0, Pile1, Pile). 

Il vous semble besoin d'accumuler les «chemises» (comme des atomes de la liste). Ici, nous les ajoutons récursivement sur le troisième argument de mix/3 (Pile), jusqu'à ce que le cas de base (le premier article) soit atteint lorsque les deux listes d'entrée sont des listes vides (notez que la coupe ! est nécessaire ici comme modèle de liaison pour le la seconde clause correspond à la première, donc nous voulons l'exclure). Le comportement de la deuxième clause, qui prend une chemise de chaque liste d'entrée pour chaque étape, exige qu'ils aient été de longueur égale pour commencer.

Pour tester cela, j'ai utilisé la définition suivante de takeshirt/4:

takeshirt(Ps, _, [P], Rem) :- 
    select(P, Ps, Rem). 

Notez que le deuxième argument ici est utilisé, comme select/3 est utilisé pour prendre un seul élément (une chemise) de la liste, et retourne le reste.L'absence de coupure (!) après select permet à ce prédicat de revenir en arrière en sélectionnant tous les autres éléments (chemises) de la liste. Si nous exécutons maintenant votre exemple de requête avec cette définition, nous pouvons obtenir:

1 ?- mix([a,b],[c,d],NewPile). 
NewPile = [a, c, b, d] ; 
NewPile = [a, d, b, c] ; 
NewPile = [b, c, a, d] ; 
NewPile = [b, d, a, c] ; 
false. 

... nous pouvons voir que mix/3 énumère tous les « piles » possibles sur retours en arrière en prenant une chemise de la première pile (première liste d'entrée), puis une chemise de la deuxième pile (deuxième liste d'entrée), et ainsi de suite, jusqu'à ce que les deux listes d'entrée soient vides. Si votre définition de takeshirt/4 ne quitte pas les points de choix, (est non-retour arrière), alors vous ne pouvez obtenir qu'une seule solution, le cas échéant.

+0

La coupure n'est pas nécessaire car 'select' échouera sur une liste vide. –

+0

@larsmans: La coupure peut ne pas être strictement nécessaire ici si l'implémentation de 'takeshirt/4' échoue sur une liste d'entrée vide. Dans mon exemple, cela pourrait être le cas si 'select/3' le faisait, comme vous le dites, mais c'était juste _my_ version pour tester; Je n'ai pas supposé quoi que ce soit à propos de l'implémentation de 'takeshirt/4' que @shaungus a mais n'a pas révélé, sauf pour l'interface. – sharky

+0

Je suppose qu'un prédicat qui prend * n * choses d'une pile échouerait s'il n'y a pas * n * choses sur la pile; ce serait la façon Prolog. Mais assez juste, +1 pour montrer à l'OP comment utiliser 'select'. –