2009-11-10 1373 views
6

para escribir "función f (mapa g XS)" como una sola llamada para mapear podría escribirHaskell, filtros encadenamiento

XS ejemplo = map (FG) xs

pero ¿cómo lo haría usted escribe "filtro p (filtro q xs)" como una sola llamada para filtrar? el operador punto no parece funcionar para filtro como lo hace para mapas. ¿Supongo que usarías algo más para los predicados?

Respuesta

9

Si ha definido una función both que se veía así:

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

entonces se podría escribir:

example xs = filter (both p q) xs 

No estoy seguro de si hay una función estándar que lo hace por usted. ..

+0

gracias hombre, eso funciona seguro eno ugh. Aún así, creo que podría haber una forma más directa de hacerlo (?) – derp

1

Definiría una función auxiliar - esto probablemente podría escribirse más declarativamente, pero no tengo instalado GHCI en este sistema para probar:

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

continuación

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

'allPredicates = (. flip ($)). voltear todo' – ephemient

+1

O el 'ligeramente menos ofuscado' allPredicates x y = all (flip ($) y) x'. ¿Con qué eficacia GHC desenreda los usos complejos de 'flip'?Al parecer, he necesitado eliminar usos de 'flip' para fines de rendimiento antes. Oh, 'allPredicates' de John podría tener un rendimiento bastante pobre ya que las funciones recursivas no pueden estar en línea. Oh extraño, no hay 'dónde ir ...' en la definición de 'todos' de' Data.List', que estoy bastante seguro de que necesitas para la alineación. –

+0

Ahh no, "transformación de argumento estático" lo hace no recursivo: http://stackoverflow.com/a/9660027/667457 –

6

Por qué no una lista por comprensión?

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

Sí, la comprensión de listas funciona bien aquí. La pregunta en realidad proviene de un tutorial que tuve esta semana, con la implicación de que había una forma directa de hacerlo. La comprensión de listas es la más rápida que he encontrado hasta ahora y estoy empezando a pensar que no puede haber una forma comparativa como con el mapa y las "composiciones de funciones". gracias a todos! – derp

+0

Siempre puede hacer una regla de reescritura. Convertir filtro f. filtrar g a \ a -> filtro (f a && g a). Por supuesto, esto es solo un sustituto de la lista más elegante de las comprensiones, aunque esto puede ser más rápido (presentimiento). – codebliss

4

Llamar a una lista de funciones de algo es esencialmente lo que la función ap en Control.Monad hace. Entonces solo and los resultados. La única leve fealdad es que ap requiere que sus dos argumentos estén en la misma mónada (Lista en este caso), por lo que debemos redactarlo con return para que funcione aquí.

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

Definiría una expresión lambda.

module Main where 

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

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

de salida:

$ 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

Esto es lo que 'GHC -O2' hace automáticamente (bueno casi: hay algunas fases diferentes de reglas de reescritura implicadas y, a menudo, las fases intermedias se combinan con otras cosas antes/en lugar de volverse a convertir en 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 declarar sus propios operadores, si se va a hacer esto a menudo.

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] 

salidas

[5,6,7,8,9] 

sólo porque las listas son plegables y se pueden combinar los resultados predicado con el All monoid

2

¿Qué pasa algo como:

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

quieres decir, 'forAll fs x = y [fx | f <- fs] '. :) Con 'all' es' forAll fs x = all ($ x) fs' (sin el 'map'). :) –