2009-11-10 4 views
6

написать "Карта F (карта г Xs)" в качестве одного вызова к карте вы могли бы написатьHaskell, цепные фильтры

пример хз = карта (фг) хз

, но как бы вы пишете «фильтр p (фильтр q xs)» как единый вызов для фильтрации? оператор-точка, похоже, не работает для фильтра, как для карт. угадывая, что вы используете что-то другое для предикатов?

ответ

9

Если вы определили функцию both, которая выглядела так:

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

Тогда вы могли бы написать:

example xs = filter (both p q) xs 

Я не уверен, если есть стандартная функция, которая делает это для вас. ..

+0

спасибо человек, который работает уверенно тьфу. все еще думая, что может быть более прямой способ сделать это, хотя (?) – derp

1

Я бы определил вспомогательную функцию - это, вероятно, может быть написано более декларативно, но у меня нет GHCI, установленного в этой системе для тестирования:

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

затем

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

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

+1

Или немного меньше запутанных 'allPredicates x y = all (flip ($) y) x'. Насколько эффективно GHC распутывает сложные применения 'flip'?Мне, казалось бы, нужно было раньше удалять использование «флип» для достижения целей. О, «allPredicates» Джона может работать довольно плохо, поскольку рекурсивные функции не могут быть встроены. О странно, нет 'where go ...' в 'Data.List' 'определения' all', что я довольно уверен, что вам нужно для inlining. –

+0

Ahh no, «статическое преобразование аргументов» делает его нерекурсивным: http://stackoverflow.com/a/9660027/667457 –

6

Почему не список понимания?

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

Да, понимание списка хорошо работает здесь. Вопрос на самом деле проистекает из учебника, который я имел на этой неделе, подразумевая, что это был простой способ сделать это. Понимание списка является самым быстрым, что я нашел до сих пор, и я начинаю думать, что не может быть никакого сравнительного способа, как с помощью карты и «функциональных композиций». спасибо всем! – derp

+0

Вы всегда можете сделать правило перезаписи. Преобразование фильтра f. фильтр g в фильтр \ a -> (f a && g a). Конечно, это просто замена более элегантным спискам, хотя это может быть быстрее (догадка). – codebliss

4

Вызов списка функций на что-то, по существу, что ap функция Control.Monad делает. Затем вы получите только and результатов. Единственное небольшое уродство в том, что ap требует, чтобы оба его аргумента были в одной монаде (список в этом случае), поэтому нам нужно скомпоновать его с return.

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

Я бы определил выражение лямбда.

module Main where 

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

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

выход:

$ 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

Это то, что «GHC -O2» делает автоматически (ну почти: есть несколько разных этапов правил перезаписи, и часто промежуточные фазы объединяются с другими вещами до/вместо того, чтобы возвращаться обратно в фильтр) –

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] 

Или объявить собственные операторы, если вы будете делать это часто.

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] 

выходов

[5,6,7,8,9] 

только потому, что списки складные, и вы можете комбинировать предикатные результаты с All моноидом

2

А что-то вроде:

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

вы имели в виду, 'forAll fs x = и [fx | f <- fs] '. :) С 'all' это' forAll fs x = all ($ x) fs' (без 'map'). :) –

Смежные вопросы