2015-07-27 4 views
7

Je joue avec la langue pour commencer à apprendre et je suis perplexe au-delà de mes esprits sur la façon dont une définition récursive fonctionne.Comment fonctionne la définition (co) récursive dans Haskell?

Par exemple, nous allons prendre la séquence des nombres (Triangular TN n = sum [1..n])

La solution proposée était:

triangularNumbers = scanl1 (+) [1..] 

Jusqu'à présent, si bon.

Mais la solution que je ne viens avec était:

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

Ce qui est correct. Maintenant, ma question est: comment cela se traduit par une implémentation de niveau inférieur? Que se passe-t-il exactement derrière la scène quand une telle définition récursive est satisfaite?

+0

Il a probablement été demandé et répondu avant, mais la recherche de "définition récursive" ne soulève que des questions liées à la récursion dans le sens algorithmique –

+0

[this] (https://hackhands.com/lazy-evaluation-works-haskell/) pourrait aider. – Alec

+0

Commencez par comprendre [[1 ..] '. –

Répondre

5

Voici une fonction récursive simple qui vous donne le nième nombre Triangulaire:

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

Votre solution triag' = zipWith (+) [1..] $ 0 : triag' est quelque chose de plus de fantaisie: Il est corecursive (click, click). Au lieu de calculer le nième nombre en le réduisant à la valeur de plus petites entrées, vous définissez la séquence infinie entière des nombres triangulaires en spécifiant récursivement la prochaine valeur, étant donné un segment initial.

Comment Haskell gère-t-il cette corecursion? Quand il rencontre votre définition, aucun calcul n'est réellement effectué, il est différé jusqu'à ce que les résultats sont nécessaires pour d'autres calculs. Lorsque vous accédez à un élément particulier de votre liste triag', Haskell commence à calculer les éléments de la liste en fonction de la définition, jusqu'à l'élément accédé. Pour plus de détails, j'ai trouvé this article sur l'évaluation paresseux utile. En résumé, l'évaluation paresseuse est géniale, sauf si vous avez besoin de prévoir l'utilisation de la mémoire.

Here est une question SO similaire, avec une explication étape par étape de l'évaluation de fibs = 0 : 1 : zipWith (+) fibs (tail fibs), une définition corécursive de la séquence de Fibonacci.

+0

Mais où est le cas de base dans la définition que j'ai fournie comme exemple? Est-ce qu'il prend de 1 de [1 ..] et 0 de 0: tn? –

+1

Supposons que vous accédiez au premier élément du 'triag'': qui peut être calculé directement, c'est' 1 + 0', la somme des premiers éléments de '[1 ..]' et '0: triag''. Maintenant le second: C'est '2 + 1' où' 2' est le deuxième élément de '[1 ..]' et '1' le deuxième élément de' 0: triag'', c'est-à-dire le premier élément de 'triag '', 1. De cette façon, tout élément de 'triag'' est défini par votre solution et peut être calculé si nécessaire. – lodrik