6

to write "map f (map g xs)" as a single call to map you could write

example xs = map (f.g) xs

but how would you write "filter p (filter q xs)" as a single call to filter? the dot operator doesnt seem to work for filter as it does for maps. guessing you'd use something else for predicates?

derp
  • 63
  • 1
  • 3

8 Answers8

9

If you defined a function both that looked like this:

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

Then you could write:

example xs = filter (both p q) xs

I'm not sure if there's a standard function that does this for you...

Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
  • thanks man, that works sure enough. still thinking there might be a more direct way of doing this though (?) – derp Nov 10 '09 at 23:52
9
$ 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]

Or declare your own operators, if you'll be doing this often.

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
ephemient
  • 198,619
  • 38
  • 280
  • 391
6

Why not a list comprehension?

example = [x | x <- xs, p x, q x]
-- for example
example = [x | x <- [1..10], (>3) x, x<5 ] -- [4]
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • Yeah, list comprehension works well here. The question actually stems from a tutorial I had this week, the implication being there was a straightforward way of doing this. List comprehension is the quickest I've found so far and I'm starting to think there may be no comparitive way as with map and "function composistions". thanks all! – derp Nov 11 '09 at 00:13
  • You could always make a rewrite rule. Convert filter f . filter g to \a -> filter (f a && g a). Of course this is just a substitiute for the more elegant list comprehensions, although this may be faster (hunch). – codebliss Nov 11 '09 at 05:18
4

Calling a list of functions on something is essentially what the ap function in Control.Monad does. Then you just and the results. The only slight ugliness is that ap requires both its arguments to be in the same monad (List in this case), so we need to compose it with return to work here.

import Control.Monad
filterByMany funcs = filter (and . ap funcs . return)
Chuck
  • 234,037
  • 30
  • 302
  • 389
4

I would define a lambda expression.

module Main where

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

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

output:

$ 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>
Michael Steele
  • 15,512
  • 2
  • 23
  • 24
  • This is what `GHC -O2` does automatically (well almost: there are a few different phases of rewrite rules involved and often the intermediate phases get combined with other stuff before/instead of being turned back into a filter) – Jeremy List Sep 30 '16 at 05:54
3
import Data.Foldable
import Data.Monoid

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

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

outputs

[5,6,7,8,9]

just because lists are foldable, and you can combine predicate results with the All monoid

barkmadley
  • 5,207
  • 1
  • 28
  • 31
2

What about something like:

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

forAll:: [(a -> Bool)] -> a -> Bool
forAll funcs x = all (map ($ x) funcs)
Viktor Mellgren
  • 4,318
  • 3
  • 42
  • 75
  • you meant, `forAll fs x = and [f x | f <- fs]`. :) With `all` it's `forAll fs x = all ($ x) fs` (without the `map`). :) – Will Ness Nov 24 '13 at 15:16
1

I'd define a helper function -- this could probably be written more declaratively, but I don't have GHCI installed on this system for testing:

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

then

filter (allPredicates [p, q]) xs
John Millikin
  • 197,344
  • 39
  • 212
  • 226
  • `allPredicates = (. flip ($)) . flip all` – ephemient Nov 11 '09 at 16:05
  • 1
    Or the slightly less obfuscated `allPredicates x y = all (flip ($) y) x`. How efficiently does GHC untangle complex usages of `flip`? I've seemingly needed to remove usages of `flip` for performance purposes before. Oh, John's `allPredicates` might perform quite poorly since recursive functions cannot be inlined. Oh strange, there is no `where go ...` in `Data.List`'s definition of `all`, which I'm fairly sure you need for inlining. – Jeff Burdges Apr 22 '12 at 08:02
  • Ahh no, "static argument transformation" makes it non-recursive : http://stackoverflow.com/a/9660027/667457 – Jeff Burdges Apr 22 '12 at 08:10