2015-07-27 17 views
7

Używam języka, aby rozpocząć naukę i jestem zdziwiony ponad moje rozumienie tego, jak działa definicja rekursywna.Jak działa (co) definicja rekursywna w Haskell?

Na przykład, weźmy kolejność Liczba trójkątna (TN n = sum [1..n])

Rozwiązanie dostarczone brzmiała:

triangularNumbers = scanl1 (+) [1..] 

Tak daleko, tak dobrze.

Ale rozwiązanie I nie było wymyślić:

triangularNumbers = zipWith (+) [1..] $ 0 : triangularNumbers 

który jest również poprawna.

Teraz moje pytanie brzmi: w jaki sposób przekłada się to na implementację na niższym poziomie? Co dzieje się dokładnie za sceną, gdy taka rekurencyjna definicja zostanie spełniona?

+0

Najprawdopodobniej zostało już zadane i udzielono odpowiedzi, ale poszukiwanie "definicji rekursywnej" wywołuje tylko pytania związane z rekurencją w sensie algorytmicznym: –

+0

[this] (https://hackhands.com/lazy-evaluation-works-haskell/) może pomóc. – Alec

+0

Zacznij od zrozumienia '[1 ..]'. –

Odpowiedz

5

Oto prosty rekurencyjna funkcja, która daje ntą Liczba trójkątna:

triag 0 = 0 
triag n = n + triag (n-1) 

Twoje rozwiązanie triag' = zipWith (+) [1..] $ 0 : triag' jest coś bardziej wyszukane: To corecursive (click, click). Zamiast obliczać n-tą liczbę, redukując ją do wartości mniejszych danych wejściowych, definiujesz całą nieskończoną sekwencję liczb trójkątnych, rekursywnie określając następną wartość, biorąc pod uwagę początkowy segment.

W jaki sposób Haskell obsługuje takie operacje rdzenia? Gdy napotyka twoją definicję, żadne obliczenia nie są wykonywane, jest odroczona, aż wyniki będą potrzebne do dalszych obliczeń. Po uzyskaniu dostępu do określonego elementu z listy, Haskell rozpoczyna obliczanie elementów listy w oparciu o definicję, aż do elementu, do którego uzyskiwany jest dostęp. Aby uzyskać więcej szczegółów, znalazłem pomocny artykuł na temat leniwego oceniania this. Podsumowując, leniwka ocena jest świetna, chyba że musisz przewidzieć użycie pamięci.

Here jest podobnym pytaniem SO, z wyjaśnieniem krok po kroku oceny fibs = 0 : 1 : zipWith (+) fibs (tail fibs), definicją corecursive sekwencji Fibonacciego.

+0

Ale gdzie jest podstawowy przypadek w definicja, którą podałem jako przykład? Czy bierze go od 1 z [1 ..] i 0 od 0: tn? –

+1

Załóżmy, że masz dostęp do pierwszego elementu 'triag'', który można obliczyć bezpośrednio, to' 1 + 0', suma pierwszych elementów '[1 ..]' i '0: triag''. Teraz drugi: Jest to '2 + 1', gdzie' 2' jest drugim elementem z '[1 ..]' i '1' drugim elementem' 0: triag'', czyli jest pierwszym elementem 'triag '', 1. W ten sposób każdy element 'triag'' jest zdefiniowany przez twoje rozwiązanie i może zostać obliczony w razie potrzeby. – lodrik