2009-02-21 16 views
5

Sto cercando di trovare un modo per fare la seguente funzione con foldl:Utilizzando foldl per contare il numero dei veri valori

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

E 'solo conta il numero di valori che sono vere in un elenco di booleani. L'ho provato da solo con

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

Che non ha nemmeno compilato. Eventuali suggerimenti?

+0

La funzione lambda (\ i -> i) è denominata "id". In modo che potrebbe essere ridotto a conteggio = lunghezza. filtro id –

risposta

9

Quindi cerchiamo di controllare i tipi di funzioni coinvolte

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 

Quindi per la vostra lista di Bool s, b è Bool, ma la funzione che si sta utilizzando ha Bool come primo argomento, non la seconda . Il valore accumulato è il primo argomento. Così, invece si potrebbe fare

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

O se proprio come per fissare l'ordine argomento, utilizzare la funzione originale con flip

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

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

Oppure si può essere più succinta: foldl (flip ((+) . fromEnum)) 0

+0

da cui vale la pena conoscere fromEnum, ma dipende da una codifica un po 'arbitraria di Bool. Non funzionerebbe (nel peggiore dei modi - sarebbe compilato ed eseguito, ma errato) se Bool fosse stato wriiten data Bool = True | False derivere Enum sarebbe sbagliato. –

+2

data Bool = False | Vero è stato fatto in questo ordine per una ragione;) Non è arbitrario. È anche definito nel rapporto http://www.haskell.org/onlinereport/basic.html, quindi se lo fai in un altro modo, non è più Haskell. –

+0

Ancora più sinteticamente: 'somma. (map fromEnum) '- (due passaggi nell'elenco, però, a meno che non si stia facendo fusione) –

4

Che ne dici di:

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

Un altro modo per farlo senza t foldl:

count list = sum $ map fromEnum list 

credito a Logan per aver ricordato fromEnum. Non ne avevo mai sentito parlare prima.

+0

Neat. Sto imparando Haskell (iniziato una settimana fa) e il meglio che ho potuto inventare era: elenco di conti = piega (+) 0 (mappa (\ i -> se io poi 1 altro 0) elenco) – eljenso

Problemi correlati