2011-12-23 11 views
10

quiero definir una función que calcula el número de elementos en una lista que satisfacen un predicado dado:Número de elementos en Haskell en el estilo pointfree

number_of_elements :: (a -> Bool) -> [a] -> Int 
    number_of_elements f xs = length (filter f xs) 

Por ejemplo:

number_of_elements (==2) [2,1,54,1,2] 

debe return .

Podemos escribir más corto:

number_of_elements f = length . filter f 

¿Es posible escribir sin f parámetro?

+3

Qué estas buscando se llama "estilo Pointfree". Hay una wiki sobre esto aquí: http://www.haskell.org/haskellwiki/Pointfree. Te enseña todos los trucos como el búho: '((.) $ (.))' Y el punto: '((.). (.))'. Yo personalmente no recomendaría este estilo. –

+6

Recomiendo jugar un poco con él, para ver cómo funciona, pero usando el estilo parcialmente libre 'number_of_elements f = length. filtro f'. Esa es la más legible por lo general. –

+6

Esta es una función que raramente me molestaría en definir, porque 'length (filter f xs)' es, francamente, más fácil de leer que 'number_of_elements f xs'. Esto último me obliga a averiguar qué hace tu función al buscar tu definición de función, la documentación o inferirla del tipo; mientras que el primero es un uso combinado directo de dos funciones que ya entiendo, ¡y también es más corto de escribir! Solo definiría esto como una función auxiliar en un enlace 'where', o como una función de módulo no exportado, e incluso solo si va a ser el argumento para otras funciones. –

Respuesta

17

Claro que lo es:

number_of_elements = (length .) . filter 
+17

Sí, ese es el estilo libre de puntas correcto e ilegible :) –

+0

Gracias, ¿puedes explicar por qué '(longitud del filtro)' o '(longitud $ filtro)' no funcionarán? – vikingsteve

+1

@vikingsteve, bueno, 'longitud. el instalador 'se expande a' \ x -> longitud (filtro x) '. Aquí 'filter x' es una función y no se puede calcular la duración de una función, sea lo que sea lo que eso signifique. Del mismo modo, 'length $ filter' está tratando de calcular la duración de la función' filter'. – Rotsor

12

No creo que se puede obtener más legible que el lo que usted sugiere. Sin embargo, sólo por el gusto de hacerlo usted puede hacer esto:

numberOfElements = (.) (.) (.) length filter 

o

(.:) = (.) . (.) 
numberOfElements = length .: filter 
+3

'(. *)' Se suele llamar '(. :)'; [lambdabot] (http://www.haskell.org/haskellwiki/Lambdabot) lo llama así, por ejemplo. – ehird

+0

@ehird lo cambió, gracias. – is7s

+2

¿Por qué no 'fmap fmap fmap'? –

7

Que le gustaría leer sobre Semantic Editor Combinators. Tome el combinador result desde allí:

result :: (output -> output') -> (input -> output) -> (input -> output') 
result = (.) 

El combinador result toma una función y lo aplica al resultado de otra función. Ahora, mirando las funciones tenemos:

filter :: (a -> Bool) -> [a] -> [a] 
length :: [a] -> Int 

Ahora, length se aplica a [a] 's; que, sucede, es el tipo de resultado de funciones del formulario foo :: [a] -> [a]. Así,

result length :: ([a] -> [a]) -> ([a] -> Int) 

Pero el resultado de filter es exactamente una función [a] -> [a], por lo que queremos aplicar result length al resultado de filter:

number_of_elements = result (result length) filter 
+1

Volvería a escribir esa última línea para aislar el SEC compuesto (combinador de editor semántico): 'number_of_elements = (result.result) length filter'. Leer como: calcule el número de elementos aplicando 'length' al resultado del resultado de' filter'. Aquí '(result.result)' es el editor combinador y 'length' es el editor (semántico). Definitivamente, lea la [publicación SEC] (http://conal.net/blog/posts/semantic-editor-combinators). – Conal

Cuestiones relacionadas