2009-11-10 10 views
6

di scrivere "funzione f (mappa g xs)" come una singola chiamata per mappare si potrebbe scrivereHaskell, filtri concatenamento

esempio xs = map (fg) xs

ma come sarebbe scrivi "filtro p (filtro q xs)" come una singola chiamata da filtrare? l'operatore punto non sembra funzionare come filtro per le mappe. supponendo che useresti qualcos'altro per i predicati?

risposta

9

Se è stato definito una funzione both che si presentava così:

both :: (a -> Bool) -> (a -> Bool) -> a -> Bool 
both f g x = f x && g x 

allora si potrebbe scrivere:

example xs = filter (both p q) xs 

non sono sicuro se c'è una funzione standard che fa per voi. ..

+0

grazie uomo, che funziona sicuramente ugh. continuando a pensare che potrebbe esserci un modo più diretto per farlo anche se (?) – derp

1

Definirei una funzione di supporto - probabilmente potrebbe essere scritta in modo più dichiarativo, ma non ho GHCI installato su questo sistema per il test:

allPredicates :: [a -> Bool] -> a -> Bool 
allPredicates []  _ = True 
allPredicates (p:ps) x = p x && allPredicates ps x 

poi

filter (allPredicates [p, q]) xs 
+0

'allPredicates = (. flip ($)). flip all' – ephemient

+1

oppure il poco meno offuscato 'allPredicates xy = all (flip ($) y) x'. Quanto efficacemente GHC riesce a districare i complessi usi di 'flip'?Ho apparentemente avuto bisogno di rimuovere gli usi di 'flip' per scopi di prestazioni prima. Oh, John 'allPredicates' potrebbe funzionare piuttosto male in quanto le funzioni ricorsive non possono essere inline. Oh strano, non c'è 'where go ...' nella definizione di 'all' di' Data.List', che sono abbastanza sicuro di aver bisogno di inlining. –

+0

Ahh no, "trasformazione argomento statico" lo rende non ricorsivo: http://stackoverflow.com/a/9660027/667457 –

6

Perché non una lista di comprensione?

example = [x | x <- xs, p x, q x] 
-- for example 
example = [x | x <- [1..10], (>3) x, x<5 ] -- [4] 
+0

Sì, la comprensione delle liste funziona bene qui. La domanda deriva in realtà da un tutorial che ho avuto questa settimana, l'implicazione è che c'era un modo semplice per farlo. La comprensione delle liste è la più veloce che ho trovato finora e sto iniziando a pensare che non ci possa essere un modo comparativo come con la mappa e le "composizioni di funzioni". grazie a tutti! – derp

+0

È sempre possibile creare una regola di riscrittura. Converti filtro f. filtra g per \ a -> filtro (f a && g a). Ovviamente questo è solo un sottotitolo per la più elegante comprensione delle liste, anche se potrebbe essere più veloce (intuizione). – codebliss

4

Chiamata di un elenco di funzioni in qualcosa è essenzialmente ciò che la funzione ap in Control.Monad fa. Quindi hai appena and i risultati. L'unica leggera bruttezza è che ap richiede che entrambi i suoi argomenti siano nella stessa monade (Elenco in questo caso), quindi è necessario comporlo con return per funzionare qui.

import Control.Monad 
filterByMany funcs = filter (and . ap funcs . return) 
4

Definirei un'espressione lambda.

module Main where 

overTen :: Int -> Bool 
overTen = (>10) 

main :: IO() 
main = do 
    print $ filter (\x -> overTen x && even x) [1..20] 

uscita:

$ ghci Test.hs 
GHCi, version 6.10.4: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer ... linking ... done. 
Loading package base ... linking ... done. 
[1 of 1] Compiling Main    (Test.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> main 
[12,14,16,18,20] 
*Main> 
+0

Questo è ciò che 'GHC -O2' fa automaticamente (beh quasi: ci sono alcune fasi differenti di regole di riscrittura coinvolte e spesso le fasi intermedie vengono combinate con altre cose prima/invece di essere trasformate in un filtro) –

8
 
$ ghci 
Prelude> :m +Control.Arrow 
Prelude Control.Arrow> :t uncurry (&&) . ((0 <) &&& (< 10)) 
uncurry (&&) . ((0 <) &&& (< 10)) :: (Num a, Ord a) => a -> Bool 
Prelude Control.Arrow> filter (uncurry (&&) . ((0 <) &&& (< 10))) [0..15] 
[1,2,3,4,5,6,7,8,9] 

o dichiarare i propri operatori, se vi ritroverete a fare questo spesso.

infixr 3 &&: 
p &&: q = \a -> p a && q a 
infixr 2 ||: 
p ||: q = \a -> p a || q a 
not' = (.) not 
all' = foldr (&&:) $ const True 
any' = foldr (||:) $ const False 

example xs = filter (p &&: q ||: not' r) xs 
3
import Data.Foldable 
import Data.Monoid 

p = (>4) 
g = (<10) 

main = print $ filter (getAll . foldMap (All.) [p,g]) [1..10] 

uscite

[5,6,7,8,9] 

solo perché le liste sono pieghevoli, ed è possibile combinare i risultati predicato con la All monoide

2

Che dire qualcosa come:

example xs = filter (forAll [p,q,r,s,t,u,v]) xs 

forAll:: [(a -> Bool)] -> a -> Bool 
forAll funcs x = all (map ($ x) funcs) 
+0

intendevi, 'forAll fs x = e [fx | f <- fs] '. :) Con 'all' è' forAll fs x = all ($ x) fs' (senza 'map'). :) –