web-dev-qa-db-fra.com

Haskell - foldl et foldr?

La différence entre foldl et foldr est-elle juste la direction du bouclage? Je pensais qu'il y avait une différence dans ce qu'ils faisaient, pas seulement dans la direction?

50
Lethi

Il y a une différence si votre fonction n'est pas associative (c'est-à-dire qu'elle importe de quelle manière vous mettez les expressions entre crochets), par exemple,
foldr (-) 0 [1..10] = -5 mais foldl (-) 0 [1..10] = -55.
À petite échelle, c'est parce que 10-(20-(30)) n'est pas la même chose que ((10)-20)-30.

Alors que (+) Est associatif (peu importe l'ordre dans lequel vous ajoutez des sous-expressions),
foldr (+) 0 [1..10] = 55 et foldl (+) 0 [1..10] = 55. (++) Est une autre opération associative car xs ++ (ys ++ zs) donne la même réponse que (xs ++ ys) ++ zs (Bien que la première soit plus rapide - n'utilisez pas foldl (++).

Certaines fonctions ne fonctionnent que dans un sens:
foldr (:) :: [a] -> [a] -> [a] mais foldl (:) n'a pas de sens.

Jetez un œil aux diagrammes de Cale Gibbard (tirés de article wikipedia ); vous pouvez voir f être appelé avec des paires de données vraiment différentes:
foldrfoldl

Une autre différence est que, parce qu'il correspond à la structure de la liste, foldr est souvent plus efficace pour une évaluation paresseuse, il peut donc être utilisé avec une liste infinie tant que f n'est pas strict dans son deuxième argument (comme (:) ou (++)). foldl n'est que rarement le meilleur choix. Si vous utilisez foldl, cela vaut généralement la peine d'utiliser foldl' Car il est strict et vous empêche de constituer une longue liste de résultats intermédiaires. (Plus d'informations sur ce sujet dans les réponses à cette question .)

104
AndrewC