Yatima2975 parece ter coberto suas duas primeiras perguntas, tentarei cobrir a terceira. Para fazer isso, tratarei um caso irrealisticamente simples, mas tenho certeza de que você será capaz de imaginar algo mais realista.
Imagine que você deseja calcular a profundidade de toda a árvore binária da ordem . O tipo de árvores binárias (sem rótulo) é (na sintaxe Haskell):n
type Tree = Leaf | Node Tree Tree
Agora a árvore completa da ordem é:n
full : Int -> Tree
full n | n == 0 = Leaf
full n = Node (full (n-1)) (full (n-1))
E a profundidade de uma árvore é calculada por
depth : Tree -> Int
depth Leaf = 0
depth (Node t1 t2) = 1 + max (depth t1) (depth t2)
d e p t h ( f u l l n) nfu l ld e p t hd e p t h ( f u l l n) fu l l _ d e p t h
full_depth : Int -> Int
full_depth n | n == 0 = 0
full_depth n = 1 + max (full_depth (n-1)) (full_depth (n-1))
Isso evita a alocação de memória da árvore completa e a necessidade de executar a correspondência de padrões, o que melhora muito o desempenho. Além disso, se você adicionar a otimização
max t t --> t
fu l l _ d e p t h
A única compilador tradicional que executa o desmatamento automática é GHC, e se bem me lembro, esta é executada somente ao compor built-in funções (por razões técnicas).
Primeiro, as listas são um tipo de árvore. Se representamos uma lista como uma lista vinculada , é apenas uma árvore cujo cada nó tem 1 ou 0 descendentes.
Árvores de análise são apenas uma utilização de árvores como uma estrutura de dados. As árvores têm muitas aplicações na ciência da computação, incluindo classificação, implementação de mapas, matrizes associativas etc.
Em geral, lista, árvores etc. são estruturas de dados recursivas: Cada nó contém algumas informações e outra instância da mesma estrutura de dados. Dobrar é uma operação sobre todas essas estruturas que transforma recursivamente os nós em valores "de baixo para cima". O desdobramento é o processo inverso, converte valores em nós "de cima para baixo".
Para uma dada estrutura de dados, podemos construir mecanicamente suas funções de dobrar e desdobrar.
Como exemplo, vamos fazer listas. (Usarei Haskell para os exemplos, pois é digitado e sua sintaxe é muito limpa.) Lista é um final ou um valor e uma "cauda".
Agora vamos imaginar que estamos dobrando uma lista. Em cada etapa, temos o nó atual a ser dobrado e já dobramos seus subnós recursivos. Podemos representar esse estado como
onde
r
é o valor intermediário construído dobrando a sub-lista. Isso nos permite expressar uma função dobrável sobre as listas:Nós convertemos
List
emListF
dobrando recursivamente sobre sua sublist e, em seguida, usamos uma função definida emListF
. Se você pensar bem, esta é apenas outra representação do padrãofoldr
:Podemos construir
unfoldList
da mesma maneira:Novamente, é apenas outra representação de
unfoldr
:(Notar que
Maybe (a, r)
é isomórfico paraListF a r
.)E também podemos construir uma função de desmatamento:
Simplesmente deixa de fora o intermediário
List
e funde as funções de dobrar e desdobrar.O mesmo procedimento pode ser aplicado a qualquer estrutura de dados recursiva. Por exemplo, uma árvore cujos nós podem ter 0, 1, 2 ou descendentes com valores em nós com 1 ou 0 ramificações:
Claro, podemos criar
deforestTree
tão mecanicamente quanto antes.(Normalmente, expressaríamos de forma
treeFold
mais conveniente como:)
Vou deixar de fora os detalhes, espero que o padrão seja óbvio.
Veja também:
fonte
É um pouco confuso, mas o desmatamento é aplicado (em tempo de compilação) para eliminar as árvores intermediárias que seriam criadas (em tempo de execução). O desmatamento não envolve cortar partes da árvore de sintaxe abstrata (que é a eliminação de galhos mortos :-)
Outra coisa que pode ter despertado você é que listas são árvores, apenas muito desequilibradas!
fonte