2017-09-02 3 views
4

Considérons le programme Prolog suivant.Prolog: résultats redondants dans les clauses impliquant des variables anonymes

a(X) :- b(_), c(X). 

b(1). 
b(2). 
b(3). 

c(1). 

Exécution de la requête:

a(X). 

dans SWI-Prolog, nous obtenons trois résultats, tout X = 1.

Étant donné que nous ne se soucient pas de la variable anonyme, ce qui est empêcher SWI-Prolog de retourner un seul résultat? Pourquoi cette optimisation n'est-elle pas effectuée?

Merci

+1

Que se passerait-il si 'b/1' présentait un effet secondaire, tel que' b (4): - asserta (c (2)). '?Ne pas dire que c'est impossible, mais ce n'est pas trivial non plus, car une unification aléatoire peut produire beaucoup d'effets secondaires. –

+0

Pour la question, pouvons-nous considérer que la base de données est statique? –

+0

Si vous voulez suggérer une optimisation qui ne fonctionne que sur un sous-ensemble trivial de votre langage, vous devez également expliquer comment le compilateur va déterminer si un morceau de code est trivial pour voir si l'optimisation sera activée. Souvent, cette détermination équivaut à exécuter le code, ce qui gonfle la complexité temporelle du compilateur. Donc non, je ne pense pas que vous pouvez considérer la base de données statique. Pour ce faire, vous devez discuter d'un langage différent de celui de Prolog, et si vous voulez savoir pourquoi une optimisation est ou n'est pas effectuée, vous voulez probablement connaître la vraie raison pour laquelle, dans la langue réelle. –

Répondre

4

Eh bien pour Prolog le trait de soulignement est simplement une variable anonyme . Ainsi, le a/1 prédicat est équivalent à:

a(X) :- 
    b(Y), 
    c(X).

Maintenant, il peut sembler inutile de revenir en arrière sur la clause b(Y), car une fois qu'il est satisfait, la Y est nulle part utilisé, et ne devrait donc pas avoir un impact sur le reste de la programme. En outre Y n'a aucun effet sur X donc b(Y) ne devrait pas avoir la moindre influence sur X.

Dans la vraie Prolog Cependant, il y a certaines choses qui pourraient avoir un impact:

  1. le prédicat b/1 peut effectuer E/S. Dire que le prédicat est mis en œuvre:

    b(a) :- 
        print(a). 
    b(a) :- 
        print(b). 
    

    il imprimera a dans la première branche et b dans le second. Déclencher une exception dans un second, troisième, ... chemin. Dans ce cas, nous voulons probablement gérer l'erreur;

  2. b/1 peut utiliser asserta/1, assertz/1, etc. et modifier le programme. Il pourrait par exemple ajouter des faits pour c/1 de telle sorte que dans la deuxième exécution c/1 a d'autres résultats.

  3. Beaucoup d'interpréteurs Prolog ont un non-backtrackable store tel que les différents chemins de retour arrière, peuvent partager des informations entre eux.

  4. d'autres possibilités de codage telles que le résultat de b/1 pourrait avoir un impact sur c/1.

Vous pouvez éviter ce retour en arrière sur b/1 en utilisant le once/1 méta-prédicat. Par exemple:

a(X) :- 
    once(b(_)), 
    c(X).