J'ai pensé moi-même que foldl
(ou foldl'
) est la meilleure approche quand vous voulez produire une liste résumer en un seul résultat (c.-à-sum
), et foldr
est la meilleure approche quand vous voulez produire une autre liste (peut-être même infinie) (c.-à-d. filter
).La combinaison foldl et foldr
Donc, je considérais un traitement qui combine ces deux. J'ai donc fait la fonction sum_f
. sum_f
est assez simple, tout ce qu'il fait est d'additionner les éléments d'une liste, mais s'il trouve un élément tel que f x
est vrai, il donne le résultat courant en sortie en tant qu'élément d'une liste et commence à sommer à partir de ce point .
Le code est ici:
sum_f :: (Num a) => (a -> Bool) -> [a] -> [a]
sum_f f =
let
sum_f_worker s (x:xs) =
let
rec_call z = sum_f_worker z xs
next_sum = s + x
in
next_sum `seq` if (f x) then next_sum : (rec_call 0) else rec_call next_sum
sum_f_worker _ [] = []
in
sum_f_worker 0
Maintenant, par exemple, permet de somme tous les nombres entiers positifs regroupés par des puissances de deux. Cela devrait génèrerait les éléments suivants:
[1, 2, 3+4, 5+6+7+8, 9+10+11+12+13+14+15+16, ...]
-à-dire
[1, 2, 7, 26, 100, ...]
Nous pouvons le faire comme ce qui suit:
import Data.Bits
main =
let
power_of_two x = (x .&. (x - 1)) == 0 -- .&. is bitwise and
in
print $ take 25 $ sum_f power_of_two [(1::Integer)..]
maintenant cette fonction ci-dessus (je crois) fonctionne dans l'espace constant (comme foldl'
), même si les groupes croissent de façon exponentielle. En outre, cela fonctionne sur les listes infinies (comme foldr
).
Je me demandais si je pouvais écrire ce qui précède en utilisant les fonctions prélude sans récurrence explicite (c'est-à-dire seulement la récursion à l'intérieur des fonctions prélude). Ou est-ce que combiner les idées de foldl
et de foldr
signifie ici que la récursion ne peut pas être faite avec les fonctions de prélude standard et doit être explicite?
Une bonne ressource pour un facteur de compréhension est l'article [ "A tutoriel sur l'universalité et l'expressivité de fold "] (http://www.cs.nott.ac.uk/~gmh/fold.pdf) par Graham Hutton. –
@jug: Je me rends compte que foldl ne fonctionne pas dans l'espace constant, mais foldl 'si vous faites attention à la rigueur. J'ai édité la question pour remplacer foldl avec fold '. – Clinton
Un peu d'un hack: 'map somme $ groupBy (\ _ y -> not (power_of_two (y-1))) [1 ..]' – luqui