2009-02-21 16 views
5

Estoy tratando de encontrar una manera de hacer lo siguiente función con foldl:foldl a contar el número de verdaderos valores

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

Sólo cuenta el número de valores que son verdaderas en una lista de booleanos. Lo intenté yo mismo con

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

Que ni siquiera compiló. ¿Alguna sugerencia?

+0

Su función lambda (\ i -> i) se llama "id". Entonces eso podría reducirse a count = length. filtrar id –

Respuesta

9

Así que vamos a ver los tipos de las funciones involucradas

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 

Así que para su lista de Bool s, b es Bool, pero la función que está utilizando tiene Bool como primer argumento, no el segundo . El valor acumulado es el primer argumento. Así que en lugar que podría hacer

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

O si lo que desea es fijar el orden de los argumentos, utilice su función original con flip

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

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

O puede ser más sucinta: foldl (flip ((+) . fromEnum)) 0

+0

deenEnum vale la pena conocerlo, pero depende de un codificado algo arbitrario de Bool. No funcionaría (de la mala manera - se compilaría y se ejecutaría, pero estamos incorrectos) si se hubiera escrito Bool data Bool = True | Falso derivando Enum sería un error. –

+2

data Bool = False | True fue hecho en ese orden por una razón;) No es arbitrario. También está definido en el informe http://www.haskell.org/onlinereport/basic.html, así que si lo haces de otra manera, ya no es Haskell. –

+0

Aún más sucintamente: 'suma. (map fromEnum) '- (dos pasa a través de la lista, a menos que esté haciendo fusión) –

4

¿qué tal:

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

Otra manera de hacerlo withou t foldl:

count list = sum $ map fromEnum list 

crédito a Logan por señalar fromEnum. No había oído hablar de eso antes.

+0

Neat. Estoy aprendiendo Haskell (comenzó hace una semana) y lo mejor que se me ocurrió fue: count list = foldl (+) 0 (mapa (\ i -> if i then 1 else 0) list) – eljenso

Cuestiones relacionadas