Utiliser des opérateurs arithmétiques comme constructeurs de tuple et contre paires
Si vous devez passer une seule structure composée de deux ou plusieurs valeurs, la chose la plus évidente à utiliser est une liste, par exemple [A,B]
. C'est vraiment verbeux, cependant.
Il y a une alternative. Les valeurs Prolog peuvent stocker une structure imbriquée à peu près arbitraire, qui n'est pas évaluée. Voici un exemple montrant comment cela fonctionne:
| ?- member(member(A,B),C).
C = [member(A,B)|_] ? ;
C = [_,member(A,B)|_] ? ;
(etc.)
member(A,B)
est juste un tuple nommé dans cette situation, et l'extérieur member
(qui est un appel de fonction) le traite comme tel.
Bien que les tuples nommés soient assez utiles dans la programmation Prolog non-golfée, ils peuvent sembler encore plus verbeux que l'approche par liste. Cependant, nous pouvons utiliser à peu près des caractères arbitraires dans le nom du constructeur de tuple (en supposant qu'ils soient correctement cités); au lieu de quelque chose de mignon member
ou d'un personnage unique a
, nous pouvons faire quelque chose comme ceci:
| ?- A = '-'('/'(1,2), '/'(3,4)).
A = 1/2-3/4
Ici, nos constructeurs de tuple sont '-'
et '/'
. Et il est intéressant de noter ce que la jolie imprimante en a fait; il utilise la notation infixe pour les tuples. C'est vraiment concis et analyse de la même manière que le ferait une opération arithmétique comparable. (Cela explique également pourquoi l'arithmétique n'utilise is
pas =
; A = 1+2
s'unifierait A
avec le tuple '+'(1,2)
, donc une syntaxe distincte est nécessaire pour évaluer réellement l'expression arithmétique non évaluée.) Parce qu'un constructeur de tuple doit être appelé quelque chose , vous pouvez tout aussi bien utiliser un caractère qui a un lacet syntaxe (et en bonus, -
et/
sont également parmi les choix les plus courants dans le code non-golfé lorsqu'ils veulent un constructeur de tuple jetable rapide plutôt que quelque chose de significatif, de la même manière qui i
est souvent utilisée comme variable de boucle, ils sont donc tout à fait raisonnables à utiliser dans votre entrée et sortie s'il vous arrive d'y vouloir un tuple pour une raison quelconque).
'-'
et '/'
sont de bons choix pour les constructeurs de tuple car ils ont un bon comportement et une priorité utile, vous permettant d'écrire des littéraux de tuple de manière laconique. Cependant, notez que vous n'avez pas à vous soucier de la priorité lorsque des valeurs intermédiaires sont produites dans le programme. Prolog conserve les tuples stockés sous forme d'arborescence plutôt que sous forme de code source, et les jolies imprimantes peuvent les afficher sans ambiguïté:
| ?- A = '-'('-'(1,2), '-'(3,4)).
A = 1-2-(3-4)
Parce que la syntaxe de tuple est si concise ( f(A,B)
n'est pas plus courte quef(A-B)
), vous pouvez remplacer plusieurs arguments de prédicat par des tuples sans frais, ce qui signifie que si un prédicat doit passer deux ou plusieurs de ses arguments à un autre prédicat, vous pouvez souvent les former en un tuple et passez simplement le tuple (bien que cela nécessite de changer tous les appels au prédicat, en plus du prédicat lui-même, pour utiliser un mélange approprié de constructeurs de tuple et de virgules).
Un autre avantage de cette syntaxe est que vous devez utiliser des listes en interne (plutôt que d'interagir avec des prédicats standard); une liste est fondamentalement juste un ensemble de cellules contre imbriquées, et une cellule contre est juste un tuple avec constructeur '.'
, comme on peut le voir ici:
| ?- Q = '.'('.'(A,B),'.'(C,D)).
Q = [[A|B],C|D]
Si votre code utilise des listes "manuellement", il peut être très judicieux d'utiliser un constructeur de tuple moins volumineux que '.'
. Un choix courant pour moi est de représenter une cellule contre comme '/'(Tail,Head)
(car il s'agit de la plus lisible que vous puissiez obtenir dans la sortie de débogage sans gaspiller les caractères). Notez que vous voudrez probablement aussi votre propre []
équivalent; tu pourrais utiliser[]
mais il fait deux octets de long et il y a beaucoup d'atomes d'un octet (toutes les lettres minuscules) que vous pouvez utiliser à la place.
Ainsi, par exemple, la liste suivante:
[1,2,3]
pourrait être converti en une représentation manuelle dans le même nombre de caractères comme celui-ci:
x/3/2/1
tout en gagnant l'avantage que les [H|T]
correspondances de modèle de style peuvent maintenant être écrites plus sèchement que T/H
, et un test contre la liste vide comme juste x
plutôt que plus long []
. (Bien sûr, cela vient avec l'inconvénient évident que member
, append
etc., ne fonctionnera pas sur cette représentation.)
prolog
balise est un peu inutile. À moins que nous ayons un défi Interpréter Prolog, nous n'en avons pas besoin.