2012-01-18 11 views
6

a veces me encuentro escribiendo código como este:Una mejor manera de contar la longitud de una lista de unidades

someFunc :: Foo -> Int 
someFunc foo = length $ do 
    x <- someList 
    guard someGuard 
    return() 

o equivalentemente:

someFunc foo = length [() | x <- someList, someGuard] 

¿Hay una mejor manera de realizar este tipo de computación? ¿Más eficiente? Más legible? Más idiomático?

Respuesta

6

Si se encuentra programando repetidamente un patrón, lo que hay que hacer es escribir una función de orden superior para encapsular ese patrón. Usted podría utilizar el cuerpo que tiene, pero con el fin de estar completamente seguro de que su código no está asignando, yo recomendaría usar foldl y la aplicación estricta de un operador de la subasta:

numberSatisfying :: Integral n => (a -> Bool) -> [a] -> n 
numberSatisfying p = foldl (\n x -> if p x then (+1) $! n else n) 0 

he utilizado QuickCheck para confirmar esto código equivalente a tu código original. (Y sí, es bastante bueno que QuickCheck lo pruebe con predicados aleatorios.)

+3

¿Por qué no 'foldl''? –

+0

@trinithis no en el Preludio ... –

8

Primo

guard someGuard 
return() 

es redundante, ya guard devuelve () si la condición es verdadera. Entonces supongo que someGuard realmente depende de x, de lo contrario sería if someGuard then length someList else 0. La forma habitual de escribirlo es

someFunc foo = filter (\x -> someGuard) someList 

si la situación es tan simple como se ve en el ejemplo. Para situaciones más complicadas, usar uno de tus estilos de ejemplo es la forma más directa. Encuentro que la notación do es preferible si las cosas se ponen realmente complicadas.

+0

+1 Sí, 'someList' depende de' foo', y 'someGuard' depende de' foo' y 'x'. La expresión del filtro es probablemente la forma más sencilla de capturar eso. –

Cuestiones relacionadas