2009-11-10 4 views
6

à écrire "carte f (carte g xs)" comme un seul appel à la carte vous pouvez écrirehaskell, filtres enchaînant

exemple xs = carte (fg) xs

mais comment vous écrivez "filtre p (filtre q xs)" comme un seul appel à filtrer? l'opérateur point ne semble pas fonctionner pour le filtre comme il le fait pour les cartes. deviner que vous utiliseriez autre chose pour les prédicats?

Répondre

9

Si vous avez défini une fonction both qui ressemblait à ceci:

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

Ensuite, vous pouvez écrire:

example xs = filter (both p q) xs 

Je ne sais pas s'il y a une fonction standard qui fait cela pour vous.

+0

merci l'homme, ça marche bien eno Pouah. pense toujours qu'il pourrait y avoir une façon plus directe de faire cela (?) – derp

1

Je définirais une fonction d'assistance - ceci pourrait probablement être écrit de façon plus déclarative, mais je n'ai pas installé GHCI sur ce système pour le tester:

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

puis

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

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

+1

Ou le légèrement moins obfusqué 'allPredicates x y = tout (flip ($) y) x'. Avec quelle efficacité GHC démêle-t-elle les utilisations complexes de 'flip'?J'ai apparemment eu besoin de supprimer les utilisations de 'flip' à des fins de performance avant. Oh, les 'allPredicates 'de John peuvent fonctionner assez mal puisque les fonctions récursives ne peuvent pas être inline. Oh étrange, il n'y a pas de 'where go ...' dans la définition de 'all' de Data.List', dont je suis presque sûr que vous avez besoin pour l'inlining. –

+0

Ahh non, "transformation d'argument statique" le rend non-récursif: http://stackoverflow.com/a/9660027/667457 –

6

Pourquoi pas une compréhension de la liste?

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

Ouais, la compréhension de la liste fonctionne bien ici. La question provient en fait d'un tutoriel que j'ai eu cette semaine, l'implication étant qu'il y avait une façon simple de le faire. La compréhension de la liste est la plus rapide que j'ai trouvée jusqu'ici et je commence à penser qu'il n'y a peut-être pas de moyen de comparaison comparable à la carte et aux "compositions de fonction". merci à tous! – derp

+0

Vous pouvez toujours créer une règle de réécriture. Convertir le filtre f. filtrez g sur \ a -> filtre (f a && g a). Bien sûr, ce n'est qu'un substitut pour les compréhensions de liste plus élégantes, bien que cela puisse être plus rapide (intuition). – codebliss

4

Appeler une liste de fonctions sur quelque chose est essentiellement ce que la fonction ap dans Control.Monad fait. Alors vous juste and les résultats. La seule petite laideur est que ap exige que ses deux arguments soient dans la même monade (Liste dans ce cas), donc nous devons le composer avec return pour travailler ici.

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

Je définirais une expression lambda.

module Main where 

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

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

sortie:

$ 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

C'est ce que fait 'GHC -O2' automatiquement (enfin presque: il y a quelques phases différentes de réécriture impliquées et souvent les phases intermédiaires sont combinées avec d'autres trucs avant/au lieu d'être retournées dans un filtre) –

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] 

Ou Déclarez vos propres opérateurs, si vous allez faire souvent.

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] 

sorties

[5,6,7,8,9] 

juste parce que les listes sont pliables, et vous pouvez combiner les résultats sous-jacentes à la All MONOID

2

Qu'en est-il quelque chose comme:

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

'pourAll fs x = et [fx | f <- fs] '. :) Avec 'all' c'est' forAll fs x = all ($ x) fs' (sans le 'map'). :) –