Disclaimer: il s'agit de cours informels et non évalués à faire à mon temps. Je l'ai essayé moi-même, j'ai échoué et je cherche maintenant quelques conseils.
J'essaie de mettre en œuvre une version de la fonction Membre / 2 qui ne renvoie que les membres d'une liste une fois. P>
Par exemple : p> Je voudrais imprimer uniquement chaque numéro un maximum de une fois. p> on nous a dit Pour faire cela avec la coupe '!' opérateur mais j'ai regardé par-dessus les notes pour que mon cours soit coupé et plus en ligne, puis ne puisse toujours pas le faire cliquer dans ma tête! p> Jusqu'à présent, j'ai réussi à obtenir: p> once_member(E, [E | L]) :- !.
once_member(E, [_, L]) :-
once_member(E, L).
4 Réponses :
La solution avec la coupe ... Au début, il semble assez gênant.
En supposant que le premier argument sera instancié, une solution est triviale: p> mais Cela n'aura pas le comportement que vous souhaitez si le premier arg n'est pas instancié. mais c'est la vedey inefficace p> < P> À ce stade, j'ai commencé à croire qu'il n'est pas possible de faire juste une coupe (en supposant que nous n'utilisons pas + ou list_to_set / 2 Si nous pouvions implémenter un prédicat (comme list_to_set / 2 de swi-prolog) qui prendrait une liste et produirait une liste dans laquelle tous les éléments en double sont supprimés, nous pourrions simplement utiliser le membre normal / 2 et ne pas obtenir des résultats en double. Essayez, je pense que vous pourrez l'écrire vous-même. P> ------------------- P> < Pré> xxx pré> Comme vous le voyez, nous devons utiliser une coupe dans Supprimer_All / 3 car sinon la troisième clause peut être jumelée par BTW, la solution avec non peut être caractérisée comme plus déclarative que la solution avec la coupe; La coupe que nous avons utilisée est typiquement appelée une coupe rouge car elle modifie le comportement du programme. Et il y a d'autres problèmes; Notez que, même avec la coupe, d'autre part, il n'est pas efficace de vérifier deux fois pour une condition. Par conséquent, l'optimal serait d'utiliser la structure if-then-else (mais je suppose que vous n'êtes pas autorisé à l'utiliser non plus; sa mise en œuvre peut être effectuée avec une coupe). P> d'autre part Il existe une autre implémentation plus facile avec non: vous ne devez pas seulement vérifier si X est membre de la liste, mais également si vous l'avez déjà rencontrée; Donc, vous aurez besoin d'un accumulateur: p> ----------------------------------------- p>
Si nous connaissons le domaine des énums éléments (par exemple, les numéros entre 1 et 42), nous pourrions instancier le premier argument: P>
Oh, attendez! p> supprimer_all (x, [x | _], _) code > Depuis que nous ne précisons pas que H est différent de X. Je crois que la solution avec non est triviale. p>
retirer_all (1, [1,2], [1,2]) code> réussirait. p>
Voici une approche qui utilise une coupe dans la définition de ?- once_member(X,[1,2,3,1]).
X = 2 ;
X = 3 ;
X = 1 ;
no
Je marquais ce droit comme il semble correspondre au plus étroitement avec ce qu'ils étaient après (de lire la question). Cependant, les autres réponses semblaient également vraiment bonnes surtout Thanosqr qui ont fourni des charges de conseils et d'informations utiles. Merci a tous!
En fait, l'un de mes tests avait ceci, il manque simplement l'ancien membre / 2 prédicat, pourquoi je faisais des anomalies, je pense.
?- X = 1, once_member(X, [A,B]). X = A, A = 1 ; X = B, B = 1. ?- X = 1, once_member(X, [A,A]). X = A, A = 1.
Supprimer les réponses redondantes et em> Séjour pur! Nous définissons particulièrement avec méta -Prédicates, un ordre d'argument différent peut être utile parfois: p> requête d'échantillon: p> Memberd / 2 code> basé sur
if_ / 3 code> et
: p> (=) / 3 code>
Maintenant, il n'a besoin que de l'efficacité pour éviter la création de points de choix inutiles!
Ce serait un CP dans (=) / 3 code>.
Il serait éliminé pour tous les cas pertinents. Et il ne serait pas éliminé s'il n'y a pas de moyen déterminé de produire une réponse correcte. C'est = (x, y, r) code> réussirait deux fois.
= (x, y, r) code> lit deux fois deux fois. Une fois avec
x = y code> et une fois avec
dav (x, y) code>