2009-11-10 96 views
6

寫 「映射f(圖g XS)」 作爲一個調用地圖,你可以寫哈斯克爾,鏈接過濾器

例如XS =地圖(FG)XS

但如何將你寫一個「filter p(filter 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

感謝男人,這確實是eno啊。仍然認爲可能有更直接的方式做到這一點雖然(?) – 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($))。翻轉所有' – ephemient

+1

或者稍微少混淆的'allPredicates x y = all(flip($)y)x'。 GHC如何有效地解決「flip」的複雜用法?我以前似乎需要移除用於性能目的的「flip」用法。哦,由於遞歸函數不能內聯,John的'allPredicates'可能表現不佳。哦,奇怪的是,'Data.List'的'all'的定義中沒有'where'...',我相當肯定你需要內聯。 –

+0

啊,不,「靜態參數轉換」使它非遞歸: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

調用的東西的功能列表基本上是什麼Control.Monad的ap功能一樣。然後你只需and的結果。唯一的一個小丑是ap要求它的參數都在同一個monad中(在這種情況下是List),所以我們需要用return來編寫它在這裏工作。

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

我會定義一個lambda表達式。

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

你的意思是, 'for all fs x = and [fx | f < - fs]'。 :)對於所有fs x = all($ x)fs'(沒有'map')''all''。 :) –