Considere um tipo indutivo que possui algumas ocorrências recursivas em um local aninhado, mas estritamente positivo. Por exemplo, árvores com ramificação finita com nós usando uma estrutura de dados de lista genérica para armazenar os filhos.
Inductive LTree : Set := Node : list LTree -> LTree.
A maneira ingênua de definir uma função recursiva sobre essas árvores recorrendo sobre árvores e listas de árvores não funciona. Aqui está um exemplo com a size
função que calcula o número de nós.
Fixpoint size (t : LTree) : nat := match t with Node l => 1 + (size_l l) end
with size_l (l : list LTree) : nat := match l with
| nil => 0
| cons h r => size h + size_l r
end.
Esta definição está incorreta (mensagem de erro extraída):
Error:
Recursive definition of size_l is ill-formed.
Recursive call to size has principal argument equal to
"h" instead of "r".
Por que a definição está mal formada, embora r
seja claramente um subtermo de l
? Existe uma maneira de definir funções recursivas nessa estrutura de dados?
Se você não é fluente na sintaxe Coq: LTree
é um tipo indutivo correspondente à seguinte gramática.
Tentamos definir a size
função por indução sobre árvores e listas. No OCaml, isso seria:
type t = Node of t list
let rec size = function Node l -> 1 + size_l l
and size_l = function [] -> 0
| h::r -> size h + size_l r
fonte
Respostas:
O que funciona
Se você aninhar a definição do ponto de correção nas listas dentro da definição do ponto de correção nas árvores, o resultado será bem digitado. Este é um princípio geral quando você aninha a recursão em um tipo indutivo, ou seja, quando a recursão passa por um construtor como
list
.Ou se você preferir escrever isso de forma mais concisa:
(Não tenho idéia de quem o ouvi primeiro; isso certamente foi descoberto de forma independente várias vezes.)
Um predicado geral de recursão
De um modo mais geral, você pode definir o princípio de indução “adequado”
LTree
manualmente. O princípio de indução gerado automaticamenteLTree_rect
omite a hipótese da lista, porque o gerador do princípio de indução apenas entende ocorrências estritamente positivas não aninhadas do tipo indutivo.Vamos adicionar a hipótese de indução nas listas. Para cumpri-lo na chamada recursiva, chamamos o princípio de indução de lista e passamos a ele o princípio de indução de árvore na árvore menor dentro da lista.
Por quê
A resposta para o motivo está nas regras precisas para aceitar funções recursivas. Essas regras são forçosamente sutis, porque existe um delicado equilíbrio entre permitir casos complexos (como este, com recursão aninhada no tipo de dados) e insatisfação. O manual de referência da Coq apresenta a linguagem (o cálculo de construções indutivas, que é a linguagem de prova da Coq), principalmente com definições formalmente precisas, mas se você deseja as regras exatas sobre indução e coindução, precisará ir aos documentos de pesquisa, neste tópico de Eduardo Giménez [1].
Fix
l
t
size
h
l
size_l
r
l
size_l
A razão pela qual
h
não é estruturalmente menor do que,l
segundo o intérprete Coq, não está clara para mim. Tanto quanto eu entendo das discussões na lista Coq-club [1] [2], esta é uma restrição no intérprete, que em princípio poderia ser levantada, mas com muito cuidado para evitar a introdução de uma inconsistência.Referências
Cocorico, o wiki Coq não-determinante: Indução Mútua
Lista de discussão Coq-Club:
A equipe de desenvolvimento da Coq. O Coq Proof Assistant: Manual de Referência . Versão 8.3 (2010). [ web ] cap. 4 .
Eduardo Giménez. Codificando definições guardadas com esquemas recursivos . Em Types'94: Types for Proofs and Programs , LNCS 996. Springer-Verlag, 1994. doi: 10.1007 / 3-540-60579-7_3 [ Springer ]
Eduardo Giménez. Definições estruturais recursivas na teoria dos tipos . Na ICALP'98: Anais do 25º Colóquio Internacional sobre Autômatos, Idiomas e Programação. Springer-Verlag, 1998. [ PDF ]
fonte
Obviamente, esse é um problema específico da Coq, pois acredito que existem maneiras mais agradáveis de contornar isso com outros assistentes de provas (estou olhando para a Agda)
A princípio, pensei que
r
não era reconhecido estruturalmente menor porque a estrutura é apenas sobre a definição indutiva atualmente manipuladaFixpoint
: portanto, este não é umLTree
subtermo, mesmo que sejalist
subtermo.Mas se você expandir o processamento da lista, funcionará:
Ou como a função auxiliar já existe na biblioteca padrão:
Para ser sincero, não sei por que esses são aceitos pela Coq, mas estou feliz por serem.
Há também uma solução que funciona com mais frequência e não apenas para listas: definindo um tipo indutivo independente. Nesse caso, você pode definir sua
size
função manualmente. (com dois pontos de fixação)Observe que se você tiver problemas para definições indutivas mais complexas, poderá usar um argumento de diminuição de tamanho. Isso é possível, mas complicado para esse problema (e eu ousaria dizer a maioria dos problemas)
fonte