2011-12-23 14 views
10

voglio definire una funzione che calcola il numero di elementi in una lista che soddisfano una determinata predicato:numero di elementi in Haskell in stile pointfree

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

Ad esempio:

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

dovrebbe ritorno .

Possiamo scrivere più breve:

number_of_elements f = length . filter f 

E 'possibile scrivere senza f parametro?

+3

ciò che stai cercando è chiamato "stile Pointfree". C'è una wiki al riguardo qui: http://www.haskell.org/haskellwiki/Pointfree. Ti insegna tutti i trucchi come il gufo: '((.) $ (.))' E il punto: '((.). (.))'. Tuttavia non consiglierei personalmente questo stile. –

+6

Consiglierei di giocarci un po ', per vedere come funziona, ma usando lo stile parzialmente ininterrotto 'number_of_elements f = length. filtro f'. Di solito è il più leggibile. –

+6

Questa è una funzione che raramente mi proverò a definire, perché 'length (filter f xs)' è, francamente, più facile da leggere di 'number_of_elements f xs'. Quest'ultimo mi richiede di capire cosa fa la tua funzione cercando la definizione della tua funzione, la documentazione o dedurla dal tipo; mentre il primo è un semplice uso combinato di due funzioni che comprendo già - ed è anche più breve da scrivere! Definirei questa funzione solo come una funzione ausiliaria in una funzione 'where' binding, o come una funzione non esportata, e anche in questo caso solo se sarà argomento di altre funzioni. –

risposta

17

Certo che lo è:

number_of_elements = (length .) . filter 
+17

Sì, questo è il corretto stile pointfree, illeggibile :) –

+0

Grazie, e puoi spiegare perché '(length. Filter)' o '(length $ filter)' non funzionerà? – vikingsteve

+1

@vikingsteve, beh, 'lunghezza. fitler' si espande in '\ x -> length (filter x)'. Qui 'filter x' è una funzione e non è possibile calcolare la lunghezza di una funzione, qualunque cosa significhi. Allo stesso modo, 'length $ filter' sta cercando di calcolare la lunghezza della funzione' filter'. – Rotsor

12

Non credo che si può ottenere più leggibile rispetto al quello che hai suggerito. Tuttavia, solo per il gusto di farlo si può fare questo:

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

o

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

'(. *)' È solitamente chiamato '(. :)'; [lambdabot] (http://www.haskell.org/haskellwiki/Lambdabot) lo chiama, per esempio. – ehird

+0

@ehird l'ha cambiato, grazie. – is7s

+2

Perché non 'fmap fmap fmap'? –

7

Come si potrebbe leggere su Semantic Editor Combinators. Prendere la result combinatore da lì:

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

Il result combinatore prende una funzione e si applica al risultato di un'altra funzione. Ora, guardando le funzioni che abbiamo:

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

Ora, length vale per [a] 's; che, succede, è il tipo di risultato delle funzioni del modulo foo :: [a] -> [a]. Così,

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

Ma il risultato di filter è esattamente una funzione [a] -> [a], quindi vogliamo applicare result length al risultato di filter:

number_of_elements = result (result length) filter 
+1

Vorrei riscrivere quell'ultima riga per isolare il SEC composto (combinatore di editor semantico): 'number_of_elements = (result.result) filtro di lunghezza'. Leggi come: calcola il numero di elementi applicando 'length' al risultato del risultato di' filter'. Qui '(result.result)' è il combinatore dell'editor e 'length' è l'editor (semantico). Leggere decisamente il [post SEC] (http://conal.net/blog/posts/semantic-editor-combinators). – Conal

Problemi correlati