Use operadores aritméticos como construtores de tupla e pares de contras
Se você precisar passar uma única estrutura que consiste em dois ou mais valores, a coisa mais óbvia a ser usada é uma lista, por exemplo, [A,B]
. Isso é realmente detalhado, no entanto.
Existe uma alternativa. Os valores de prólogo podem armazenar uma estrutura aninhada praticamente arbitrária, que não é avaliada. Aqui está um exemplo mostrando como isso funciona:
| ?- member(member(A,B),C).
C = [member(A,B)|_] ? ;
C = [_,member(A,B)|_] ? ;
(etc.)
member(A,B)
é apenas uma tupla nomeada nessa situação, e a parte externa member
(que é uma chamada de função) está tratando-a como tal.
Embora as tuplas nomeadas sejam bastante úteis na programação Prolog sem golfe, elas podem parecer ainda mais detalhadas do que a abordagem da lista. No entanto, podemos usar praticamente caracteres arbitrários no nome do construtor de tupla (supondo que eles estejam corretamente citados); em vez de algo fofo member
ou um único personagem a
, podemos fazer algo assim:
| ?- A = '-'('/'(1,2), '/'(3,4)).
A = 1/2-3/4
Aqui, nossos construtores de tupla são '-'
e '/'
. E é interessante observar o que a impressora bonita fez com eles; está usando notação infix para as tuplas. Isso é realmente conciso e analisa da mesma maneira que faria uma operação aritmética comparável. (Isso também explica por que a aritmética is
não usa =
; a A = 1+2
unificação A
com a tupla '+'(1,2)
, portanto, é necessária uma sintaxe separada para realmente avaliar a expressão aritmética não avaliada.) Como um construtor de tupla precisa ser chamado de algo , você também pode usar um caractere que tenha uma concha sintaxe (e como bônus, -
e/
também são algumas das opções mais comuns no código não-golfe quando eles desejam um construtor de tupla descartável rápido em vez de algo significativo, da mesma maneira quei
é frequentemente usado como uma variável de loop, portanto, é inteiramente razoável usá-lo em sua entrada e saída, se você desejar uma tupla por algum motivo).
'-'
e '/'
são boas escolhas para construtores de tuplas porque eles têm uma precedência útil e bem comportada, permitindo que você escreva literalmente as tuplas de forma concisa. No entanto, observe que você não precisa se preocupar com precedência quando valores intermediários são produzidos dentro do programa. O Prolog mantém as tuplas armazenadas como uma árvore, e não como código-fonte, e as impressoras bonitas podem produzi-las sem ambiguidade:
| ?- A = '-'('-'(1,2), '-'(3,4)).
A = 1-2-(3-4)
Como a sintaxe da tupla é muito concisa ( f(A,B)
não é menor quef(A-B)
), é possível substituir vários argumentos de predicados por tuplos sem nenhum custo, o que significa que, se um predicado precisar passar dois ou mais de seus argumentos para outro predicado, é possível transformá-los em uma tupla e apenas passar a tupla (embora isso exija a alteração de todas as chamadas para o predicado, além do próprio predicado, para usar uma combinação apropriada de construtores e vírgulas de tupla).
Outra vantagem dessa sintaxe é se você precisar usar listas internamente (em vez de interoperar com predicados padrão); uma lista é basicamente apenas um conjunto de células contras aninhadas e uma célula contras é apenas uma tupla com construtor '.'
, como pode ser visto aqui:
| ?- Q = '.'('.'(A,B),'.'(C,D)).
Q = [[A|B],C|D]
Se seu código usa listas "manualmente", pode fazer muito sentido usar um construtor de tupla menos volumoso que '.'
. Uma escolha comum para mim é representar uma célula contras como '/'(Tail,Head)
(porque é a mais legível que você pode obter na saída de depuração sem desperdiçar caracteres). Observe que você provavelmente também desejará seu próprio []
equivalente; você poderia usar[]
mas tem dois bytes e há muitos átomos de um byte (todas as letras minúsculas) que você pode usar.
Então, por exemplo, a seguinte lista:
[1,2,3]
pode ser convertido em uma representação manual no mesmo número de caracteres como este:
x/3/2/1
ao mesmo tempo em que [H|T]
obtém a vantagem de que as correspondências de padrões no estilo agora podem ser escritas de maneira mais concisa T/H
, e um teste contra a lista vazia como um pouco, x
e não mais []
. (Claro, isso vem com a desvantagem óbvia de que member
, append
etc., não vai trabalhar nesta representação.)
prolog
tag é meio inútil. A menos que tenhamos um desafio Interpret Prolog, não precisamos dele.