2009-02-21 15 views
5

J'essaie de trouver un moyen de faire la fonction suivante avec foldl:En utilisant foldl pour compter le nombre de vraies valeurs

count a = length (filter (\i -> i) a) 

Il compte que le nombre de valeurs qui sont vraies dans une liste de booléens. Je l'ai essayé moi-même avec

count = foldl (\i -> 
      case i of 
       True -> (1+) 
       False -> (0+) 
      ) 0 

Qui n'a même pas compilé. Aucune suggestion?

+0

Votre fonction lambda (\ i -> i) s'appelle "id". Donc, cela pourrait être réduit à count = longueur. ID du filtre –

Répondre

9

Alors nous allons vérifier les types de fonctions impliquées

Prelude> :t (\i -> case i of { True -> (1+) ; False -> (0+) }) 
(\i -> case i of { True -> (1+) ; False -> (0+) }) :: (Num t) => Bool -> t -> t 
Prelude> :t foldl 
foldl :: (a -> b -> a) -> a -> [b] -> a 

Donc, pour votre liste de Bool s, b est Bool, mais la fonction que vous utilisez a Bool comme premier argument, et non la seconde . La valeur accumulée est le premier argument. Ainsi, au lieu que vous pourriez faire

foldl (\acc p -> case p of { True -> acc + 1 ; False -> acc }) 0 

Ou si vous souhaitez simplement fixer l'ordre des arguments, utilisez votre fonction originale avec flip

Prelude> :t flip 
flip :: (a -> b -> c) -> b -> a -> c 

foldl (flip (\i -> case i of 
          True -> (1+) 
          False -> (0+) 
      )) 0 

Ou vous pouvez être plus succincte: foldl (flip ((+) . fromEnum)) 0

+0

le fromEnum mérite d'être connu, mais dépend d'un encodage quelque peu arbitraire de Bool. Cela ne fonctionnerait pas (de la mauvaise façon - il compilerait et fonctionnerait, mais nous aurions tort) si Bool avait été écrit data Bool = True | Faux dériver Enum ce serait faux. –

+2

données Bool = Faux | Vrai a été fait dans cet ordre pour une raison;) Ce n'est pas arbitraire. Il est également défini dans le rapport http://www.haskell.org/onlinereport/basic.html, donc si vous le faites d'une autre manière, ce n'est plus Haskell. –

+0

Encore plus succinctement: «somme. (map fromEnum) '- (deux passages dans la liste, sauf si vous faites une fusion) –

4

Et à propos de:

count = foldl (\i v -> if v then i + 1 else i) 0 

Une autre façon de le faire sans t foldl:

count list = sum $ map fromEnum list 

Crédit Logan pour souligner fromEnum. N'avait pas entendu parler de celui-là avant.

+0

Neat. J'apprends Haskell (commencé il y a une semaine) et le meilleur que je pourrais trouver était: liste de compte = foldl (+) 0 (carte (\ i -> si je puis 1 autre 0) liste) – eljenso