Wygląda na to, że Yatima2975 obejmowała pierwsze dwa pytania, postaram się odpowiedzieć na trzecie. Aby to zrobić, zajmę się nierealistycznie prostą sprawą, ale jestem pewien, że będziesz w stanie wyobrazić sobie coś bardziej realistycznego.
Wyobraź sobie, że chcesz obliczyć głębokość pełnego drzewa binarnego rzędu . Typ (nieznakowanych) drzew binarnych to (w składni Haskella):n
type Tree = Leaf | Node Tree Tree
Teraz pełne drzewo rzędu to:n
full : Int -> Tree
full n | n == 0 = Leaf
full n = Node (full (n-1)) (full (n-1))
Głębokość drzewa jest obliczana przez
depth : Tree -> Int
depth Leaf = 0
depth (Node t1 t2) = 1 + max (depth t1) (depth t2)
Teraz możesz zobaczyć, że każde obliczenie najpierw skonstruuje pełne drzewo rzędu za pomocą a następnie zdekonstruuje to drzewo za pomocą . Wylesianie opiera się na spostrzeżeniu, że taki wzorzec (konstrukcja, po której następuje dekonstrukcja) często może być zwarty : możemy zastąpić każde wywołanie pojedynczym wywołaniem :n f u l l d e p t h d e p t h ( f u l l n ) f u l l _ d e p t hdepth (full n)nfulldepthdepth (full n)full_depth
full_depth : Int -> Int
full_depth n | n == 0 = 0
full_depth n = 1 + max (full_depth (n-1)) (full_depth (n-1))
Pozwala to uniknąć alokacji pamięci pełnego drzewa i konieczności wykonywania dopasowywania wzorców, co znacznie poprawia wydajność. Ponadto, jeśli dodasz optymalizację
max t t --> t
Potem zamieniłeś wykładniczą procedurę czasową na liniową, czasową ... Byłoby fajnie, gdyby istniała dodatkowa optymalizacja, która rozpoznałaby, że to tożsamość liczb całkowitych, ale nie jestem pewien, czy takie optymalizacja jest stosowana w praktyce.full_depth
Jedynym głównym kompilatorem, który wykonuje automatyczne wylesianie, jest GHC, a jeśli dobrze pamiętam, jest to wykonywane tylko podczas komponowania wbudowanych funkcji (z przyczyn technicznych).
Po pierwsze, listy są rodzajem drzew. Jeśli reprezentujemy listę jako listę połączoną , jest to tylko drzewo, którego każdy węzeł ma 1 lub 0 potomków.
Parsowanie drzew to tylko wykorzystanie drzew jako struktury danych. Drzewa mają wiele zastosowań w informatyce, w tym sortowanie, wdrażanie map, tablice asocjacyjne itp.
Ogólnie rzecz biorąc, lista, drzewa itp. Są rekurencyjnymi strukturami danych: każdy węzeł zawiera pewne informacje i inne wystąpienie tej samej struktury danych. Składanie to operacja na wszystkich takich strukturach, która rekurencyjnie przekształca węzły w wartości „oddolne”. Rozkładanie jest procesem odwrotnym, konwertuje wartości do węzłów „z góry na dół”.
Dla danej struktury danych możemy mechanicznie konstruować ich funkcje zwijania i rozwijania.
Jako przykład weźmy listy. (Użyję Haskell w przykładach, ponieważ jest wpisany, a jego składnia jest bardzo czysta.) Lista jest albo końcem, albo wartością i „ogonem”.
Teraz wyobraźmy sobie, że składamy listę. Na każdym kroku mamy bieżący węzeł do złożenia i już złożyliśmy jego rekursywne podwęzły. Możemy reprezentować ten stan jako
gdzie
r
jest wartością pośrednią skonstruowaną przez złożenie podlisty. To pozwala nam wyrazić funkcję składania na listach:Przekształcamy
List
sięListF
poprzez rekurencyjne składanie jego podlisty, a następnie używamy funkcji zdefiniowanej naListF
. Jeśli się nad tym zastanowić, jest to kolejna reprezentacja standardufoldr
:Możemy skonstruować
unfoldList
w ten sam sposób:Ponownie, to tylko kolejna reprezentacja
unfoldr
:(Zauważ, że
Maybe (a, r)
jest izomorficznyListF a r
.)Możemy również zbudować funkcję wylesiania:
Po prostu pomija element pośredni
List
i łączy funkcje składania i rozkładania.Tę samą procedurę można zastosować do dowolnej struktury danych rekurencyjnych. Na przykład drzewo, którego węzły mogą mieć 0, 1, 2 lub potomków z wartościami na 1- lub 0-rozgałęziających się węzłach:
Oczywiście możemy tworzyć
deforestTree
tak samo mechanicznie jak wcześniej.(Zazwyczaj
treeFold
wygodniej byłoby wyrazić jako:)
Pominę szczegóły, mam nadzieję, że wzór jest oczywisty.
Zobacz też:
źródło
Jest to trochę mylące, ale stosuje się wylesianie (w czasie kompilacji), aby wyeliminować drzewa pośrednie, które zostaną utworzone (w czasie wykonywania). Wylesianie nie polega na hakowaniu części abstrakcyjnego drzewa składni (to eliminacja martwej gałęzi :-)
Kolejną rzeczą, która mogła cię wyrzucić, jest to, że listy to drzewa, po prostu bardzo niezrównoważone!
źródło