2
votes

Générer une liste et vérifier si les valeurs augmentent

Actuellement, je génère une liste, dans laquelle chaque élément a une valeur égale au carré de l'élément précédent plus la valeur de Z. Après avoir généré la liste en utilisant generate_list, je veux vérifier s'il s'agit d'une liste ordonnée ou ne pas. J'ai implémenté ordonné puis dans la console, j'essaye de faire quelque chose comme ordonné (generate_list (A, B, Z, [])., Qui renvoie toujours faux, même si je suis sûr que ça doit être vrai. Je sais que cette approche n'est pas bonne dans Prolog mais je ne sais pas comment le faire ...

gen(0,0,_).
gen(N,F,Z) :- X is N-1,gen(X,A,Z),F is (A*A)+Z.

generate_list(A,B,Z,[]):- A>B.
generate_list(A,B,Z,[H|T]):-
    A =< B,
    gen(A,H,Z),
    AA is A + 1,
    generate_list(AA,B,Z,T).

ordered([]).
ordered([_]).
ordered([X,Y|Z]):-X=<Y,ordered([Y|Z]).


2 commentaires

Avec quels paramètres générez-vous une liste ici?


J'ai utilisé la même logique que pour Fibonacci. J'utilise donc un index de début (A), un index de fin (B) et une valeur qui sera ajoutée au carré de l'élément précédent (Z).


3 Réponses :


3
votes

Je ne vois pas vraiment pourquoi vous spécifiez une fonction gen / 3 ici. Vous pouvez utiliser un accumulateur , et donc à chaque fois mettre à jour l'accumulateur, comme:

?- generate_list(5, -1, L).
L = [0, -1, 0, -1, 0] ;
false.

?- generate_list(5, -1, L), ordered(L).
false.

Par exemple pour Z est 1 , on obtient:

?- generate_list(5, 1, L), ordered(L).
L = [0, 1, 2, 5, 26] ;
false.

Avec le prédicat ordonné / 1 dans votre question, nous voyons que cette liste est bien ordonnée:

?- generate_list(5, 1, L).
L = [0, 1, 2, 5, 26] ;
false.

Alors que pour Z = -1 , ce n'est pas:

generate_list(N, Z, L) :-
    generate_list(N, Z, 0, L).

generate_list(0, _, _, []).
generate_list(N, Z, A, [A|T]) :-
    N > 0,
    B is A*A + Z,
    N1 is N-1,
    generate_list(N1, Z, B, T).


6 commentaires

Oui, mais comme vous pouvez le voir, le résultat est toujours faux même si vous le faites comme vous l'avez dit. Ou est-ce juste une erreur de frappe?


@IvanNickSim: non cela produit un résultat [0,1,2,5,26] , mais alors Prolog recherche plus de résultats, et cette recherche de plus de résultats ne donne aucun extra, donc faux . Le point-virgule (; ) dans Prolog signifie "ou". Donc l'interpréteur dit: L = [0, 1, 2, 5, 26] ou false, donc un seul résultat. Dans certains cas, le résultat est X = 1; X = 3; false. par exemple, alors il y a deux solutions.


Merci du coup de main jusqu'à présent. Donc en fait, mon idée avec la chose ordonnée est de renvoyer vrai si c'est vraiment commandé et faux si ce n'est pas le cas. Pouvez-vous m'aider?


@IvanNickSim: il fait ça, le nœud de retour arrière est dans la partie generate_list / 3 . Vous pouvez cependant construire un prédicat avec generate_list (N, Z, L), ordonné (L) comme corps qui n'exporte pas L comme paramètre, auquel cas il sera print true; false pour le premier et false pour le second. En utilisant une fois / 1 , vous ne pouvez laisser apparaître qu'un seul élément.


que voulez-vous dire en utilisant une fois / 1?


Comprendre d'où vient le point de choix et s'il peut être complètement évité est également important ;-)



1
votes

Votre commandé / 1 fonctionne probablement tel quel. Mais cela laisse un point de choix! Vous pouvez utiliser une fois (trié (L)) .

"Trié" est un peu similaire à "trié", n'est-ce pas?

Si vous pouvez avoir des doublons dans la liste, utilisez msort:

generate_list(N, Z, L) :-
    length(L, N),
    generate_list_1(L, Z, 0).

generate_list_1([], _, _).
generate_list_1([X|Xs], Z, X) :-
    X1 is X^2 + Z,
    X1 >= X, % Checks for order!
    generate_list_1(Xs, Z, X1).

Si vous n'autorisez pas les doublons, utilisez sort :

XXX

Aucun des deux ne laisse de points de choix.

Cela vous laisse avec le point de choix laissé par la solution dans l'autre réponse. Vous pouvez faire une liste puis la remplir.

sorted_uniq(L) :- sort(L, L).

Cette implémentation ne vous donne que des listes croissantes et ne laisse pas de points de choix inutiles.


0 commentaires

1
votes

Pour étendre les réponses précédentes, en particulier celle de Willem Van Onsem, vous pouvez écrire quelque chose comme:

my_ord(P,L):- 
    call(P,L),
    ordered(L).

Et ensuite vous pouvez interroger ? - my_ord (generate_list (5 , 1), L). Pour supprimer des points de choix, vous pouvez utiliser une fois / 1 à la fois sur call / 2 et commandé / 1 ou écrire un autre prédicat comme my_ord_ (P, L): - une fois (my_ord (P, L)) ou placez la coupe ! . Compte tenu de la réponse de Willem Van Onsem, vous devez ajouter une coupure après generate_list (0, _, _, []) . Dans votre commande / 1, vous avez besoin d'une coupe après commandé ([]) et ordered([_ ).


0 commentaires