4 votes

Résultat inattendu pour le prédicat nb_setarg/3

Quelqu'un sait-il pourquoi le prédicat nb_setarg/3 ne fonctionne pas correctement lorsqu'il est utilisé avec le prédicat forall/3 dans le toplevel de l'interpréteur SWI-Prolog (v. 8.2.1) ?

Comment cela fonctionne-t-il lorsqu'il est utilisé dans un objectif tapé à un niveau supérieur ?

?- 
functor(A, array, 5), 
forall(arg(Index, A, _), 
       nb_setarg(Index, A, 0)).

A = array(_26341340, _26341342, _26341344, _26341346, _26341348).

Comment il fonctionne lorsqu'il est utilisé dans une règle :

new_array(A,N) :- 
   functor(A, array, N),
   forall(
      arg(Index, A, _), 
      nb_setarg(Index, A, 0)).

Entonces:

?- 
new_array(A,5).
A = array(0, 0, 0, 0, 0).

4voto

Isabelle Newbie Points 2860

Je pense qu'il s'agit d'un bogue. Mais il se peut que ce ne soit pas un bogue (seulement) en forall/2 o nb_setarg/3 . Parce que cela fonctionne :

?- A = array(_, _, _, _, _), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(0, 0, 0, 0, 0).

alors que votre exemple ne le fait pas (SWI 7.6.4) :

?- functor(A, array, 5), forall(arg(Index, A, _), nb_setarg(Index, A, 0)).
A = array(_2290, _2292, _2294, _2296, _2298).

3voto

David Tonhofer Points 1816

Je ne sais pas, mais au toplevel la modification du terme composé est annulée lors d'un retour en arrière pour une raison quelconque (SWI-Prolog 8.3.14) :

Toplevel

?- 
functor(A, array, 5), 
   forall( 
      arg(Index, A, _),
      (format("~q: ~q\n",[Index,A]),
       nb_setarg(Index, A, 0),
       format("~q: ~q\n",[Index,A]))).

Ensuite, nous voyons de nouvelles array/5 des termes composés avec des variables nouvelles à chaque passage de forall

1: array(_3228,_4334,_4336,_4338,_4340)
1: array(0    ,_4334,_4336,_4338,_4340)
2: array(_4332,_3228,_4336,_4338,_4340)
2: array(_4332,0,    _4336,_4338,_4340)
3: array(_4332,_4334,_3228,_4338,_4340)
3: array(_4332,_4334,    0,_4338,_4340)
4: array(_4332,_4334,_4336,_3228,_4340)
4: array(_4332,_4334,_4336,0,    _4340)
5: array(_4332,_4334,_4336,_4338,_3228)
5: array(_4332,_4334,_4336,_4338,0)
A = array(_4332, _4334, _4336, _4338, _4340).

En règle générale

new_array(A,N) :- 
   functor(A, array, N), 
   forall( 
      arg(Index, A, _),
      (format("~q: ~q\n",[Index,A]),
       nb_setarg(Index, A, 0),
       format("~q: ~q\n",[Index,A]))).

Entonces:

?- new_array(A,5).
1: array(_2498,_2500,_2502,_2504,_2506)
1: array(0,_2500,_2502,_2504,_2506)
2: array(0,_2500,_2502,_2504,_2506)
2: array(0,0,_2502,_2504,_2506)
3: array(0,0,_2502,_2504,_2506)
3: array(0,0,0,_2504,_2506)
4: array(0,0,0,_2504,_2506)
4: array(0,0,0,0,_2506)
5: array(0,0,0,0,_2506)
5: array(0,0,0,0,0)
A = array(0, 0, 0, 0, 0).

D'autre part, la mise en œuvre est le suivant :

forall(Cond, Action) :-
    \+ (Cond, \+ Action).

Le prédicat ci-dessus n'est pas un bon prédicat à utiliser comme boucle.

Cependant, le comportement dans le "rule setting" semble correct.

En la documentation dit :

Le prédicat forall/2 est mis en œuvre sous la forme \+ ( Cond, \+ Action) , c'est-à-dire, Il n'y a pas d'instanciation de Cond pour lequel Action est faux . L'utilisation de la double négation implique que forall/2 ne modifie aucune liaison de variable. Il prouve une relation. Les forall/2 La structure de contrôle peut être utilisée pour ses effets secondaires.

Tout à fait.

Il n'y a rien de particulier dans la description de nb_setarg/3 soit.

C'est comme si nb_setarg/3 travaillaient en tant que setarg/3 au niveau supérieur ?

La trace ne révèle rien :

^  Call: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep

1: array(_30756,_32086,_32088,_32090,_32092)

^  Exit: (13) format("~q: ~q\n", [1, array(_30756, _32086, _32088, _32090, _32092)]) ? creep
   Call: (13) setarg(1, array(_30756, _32086, _32088, _32090, _32092), 0) ? creep
   Exit: (13) setarg(1, array(0, _32086, _32088, _32090, _32092), 0) ? creep
^  Call: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep

1: array(0,_32086,_32088,_32090,_32092)

^  Exit: (13) format("~q: ~q\n", [1, array(0, _32086, _32088, _32090, _32092)]) ? creep

Next "forall" passage: we are using a new compound term! 

^  Call: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep

2: array(_32084,_30756,_32088,_32090,_32092)

^  Exit: (13) format("~q: ~q\n", [2, array(_32084, _30756, _32088, _32090, _32092)]) ? creep
   Call: (13) setarg(2, array(_32084, _30756, _32088, _32090, _32092), 0) ? creep
   Exit: (13) setarg(2, array(_32084, 0, _32088, _32090, _32092), 0) ? 

Comme il s'agit d'une question relative à SWI-Prolog, vous pouvez la poser sur le site suivant Discours .

Mise à jour

Essai en ligne en GNU Prolog .

GNU Prolog exige que l'index de arg/3 peut être instancié et n'a pas de nb_setarg/3 (ni un forall/2 ? ?).

Mais essayons ce qui suit dans SWI-Prolog :

functor(A, array, 5), 
   \+ ( 
      between(1,5,Index),arg(Index, A, _),
      \+
         (format("~q: ~q\n",[Index,A]),
          nb_setarg(Index, A, 0),
          format("~q: ~q\n",[Index,A]))).

Cela ne fonctionne pas non plus.

Mise à jour : Essayer quelque chose de plus simple et de plus dépouillé

Comme prévu :

?- 
A=p(1,2,3),nb_setarg(1,A,foo).
A = p(foo, 2, 3).

Avec double négation. Conserve également la valeur définie de manière non rétroactive :

?- 
A=p(1,2,3),\+ \+ nb_setarg(1,A,foo).
A = p(foo, 2, 3).

2voto

David Tonhofer Points 1816

Jan Wielemaker dit en numéro 733 ( "Appelé depuis forall/2, nb_setarg/3 appliqué à un terme composé construit dans un objectif de niveau supérieur n'a aucun effet (il devient setarg/3 ?). ) qu'il s'agit d'un problème connu :

Le problème se résume à ceci :

?- functor(C, a, 2), 
    \+ \+ (arg(1, C, x), 
    nb_setarg(1, C, foo)).

C = a(_52710, _52712).

C'est-à-dire s'il y a une affectation précédente sur l'emplacement cible, le retour en arrière jusqu'à ce que cette affectation soit terminée, l'emplacement redevient une variable. variable. Dans ce cas, le arg(I,Term,_) unifie la cible avec la variable dans le terme de la requête de niveau supérieur. Comme il s'agit d'un terme plus ancien, l'emplacement de la cible devient une variable du terme de recherche de niveau supérieur. une référence suivie à la variable de la requête.

nb_setarg/3 est utile, mais c'est une boîte de Pandore.

...

Je devrais faire beaucoup de recherches pour trouver [ce qui ne va pas]. Le suivi de toutes les traînées et leur optimisation n'est pas trivial. Fondamentalement, ne revenez pas en arrière, à l'endroit où vous avez commencé à utiliser nb_* et seulement utiliser les nb_* sur le même lieu.

L'idée semble donc être que la piste (c'est-à-dire la pile de modifications à reprendre lors d'un retour en arrière, si j'ai bien compris) contient une affectation ( arg(1, C, x) ) pour la position exacte qui est modifiée par un nb_setarg/3 et vous revenez à avant cette affectation votre affectation non rétroactive est perdue.

C'est logique, et vu sous cet angle

A = array(_26341340, _26341342, _26341344, _26341346, _26341348).

est en fait le bon résultat.

(Le passage du Prolog logique au Prolog d'affectation me fait mal à la tête).

Je pense que c'est la meilleure façon de procéder :

A=array(_,_,_,_,_), 
forall(
   between(1,5,Index),   
   nb_setarg(Index, A, bar)).

ou

functor(A, array, 5),
forall(
   between(1,5,Index),   
   nb_setarg(Index, A, bar)).

0voto

slago Points 1771

Après avoir essayé les requêtes suivantes, je soupçonne que le prédicat functor/3 (ou sa version rationalisée compound_name_arity/3 ) est la véritable source du problème observé avec les nb_setarg/3 . Il semble qu'il crée un terme avec des variables fraîches qui "ne sont pas dans la portée" de la requête de niveau supérieur (remarquez que lorsque les noms des variables apparaissent explicitement dans les requêtes, les résultats sont conformes à ce qui est attendu).

?- A =.. [array,X1,X2,X3], 
   forall( arg(I, A, _), 
           nb_setarg(I, A, 0) ).

A = array(0,0,0)

?- compound_name_arguments(A, array, [X1,X2,X3]), 
   forall( arg(I, A, _), 
           nb_setarg(I, A, 0) ).

A = array(0,0,0)

?- compound_name_arity(A, array, 3), 
   forall( arg(I, A, _), 
           nb_setarg(I, A, 0) ).

A = array(_20928, _20930, _20932)

?- functor(A, array, 3), 
   forall( arg(I, A, _), 
           nb_setarg(I, A, 0) ).

A = array(_22056, _22058, _22060).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X