2009-05-08 19 views
23

İşlevlerin filtre sınıfı bir koşulu alır (a -> Boole) ve filtrelemede uygular.Filtre koşullarını nasıl birleştirirsiniz?

Çoklu koşullarınız olduğunda filtreyi kullanmanın en iyi yolu nedir?

liftM2 yerine liftA2 uygulama işlevini kullandım çünkü nedense liftM2'nin salt kod içinde nasıl çalıştığını anlamadım.

cevap

29

liftM2 combinator bir 'daha işlevsel' bir şekilde bunu yapmanın Okuyucu monad kullanılabilir: ithalat önemli olduğunu

import Control.Monad 
import Control.Monad.Reader 

-- .... 

filter (liftM2 (&&) odd (> 100)) [1..200] 

Not; Control.Monad.Reader, tüm bunların çalışmasını sağlayan Monad (e ->) örneğini sağlar.

Bu çalışmanın nedeni, okuyucu monadının bazı ortamlar için (e ->) olmasıdır. Dolayısıyla, bir boole yüklemi, argümanına karşılık gelen bir ortamda bool döndüren 0-ary monadik bir fonksiyondur. Daha sonra, bu tür iki yüklemeden dolayı ortamı dağıtmak için liftM2'yi kullanabiliriz.

Ya türleri dışarı çalışırken, daha basit açısından, liftM2 böyle biraz hareket edecek:

liftM2 f g h a = f (g a) (h a) 

Ayrıca bunlar kolayca zinciri edebilmek istiyorsanız yeni bir bağdaştırıcının tanımlayabilir ve/ya liftM2 bulaşmak istemiyorum:

(.&&.) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool) 
(.&&.) f g a = (f a) && (g a) 
-- or, in points-free style: 
(.&&.) = liftM2 (&&)  

filter (odd .&&. (> 5) .&&. (< 20)) [1..100] 
+3

Her iki örnek ghc 7.6.3 üzerinde çalışmak size 'Control.Monad.Reader' içe olmasa bile. – sjakobi

+2

Ben liftM2' şu şekilde değiştirilmiş olabilir: 'filtre ((&&) <$> tek <*> (> 100)) [1.200]'. Aynı, ama daha güzel. :) Ayrıca sadece "Control.Applicative" ve tam monadlar gerektirmez. … Operatörün iki Boolean işlevinden çok ANDing'e izin vermesini hala merak etmeme rağmen… – Evi1M4chine

15

Eh, (sürece türlerinin doğru olarak) Haskell ancak sizin istediğiniz işlevleri birleştirebilir ve lambdas kullanarak bile yani sizin yüklem işlevi, isim yok

filter (\x -> odd x && x > 100) [1..200] 
9

senin koşulları conditions denilen bir listede saklanır diyelim. Bu liste [a -> Bool] tipindedir.

bir değere x için bütün şartları uygulamak için map kullanabilirsiniz:

map ($ x) conditions 

Bu x her koşul geçerlidir ve Bool bir listesini döndürür. aksi takdirde tüm unsurları Doğru olup olmadığını Doğru, False, tek boolean Bu listeyi azaltmak için and işlevini kullanabilirsiniz:

and $ map ($ x) conditions 

Şimdi bütün koşulları birleştiren bir işlevi var. Hadi bir isim verelim: Bu fonksiyon türü a -> Bool sahiptir

combined_condition x = and $ map ($ x) conditions 

, bu yüzden filter bir çağrı kullanabilirsiniz:

filter combined_condition [1..10] 
+2

($ x) ($ x) yerine ($ x) ile dikkatli ol, sanki başka bir nedenden dolayı Template Haskell'i açarsanız, $ x aniden bir ekleme gibi görünecek . –

+8

'all' işlevini keşfettiniz:' filter (tüm koşullar) [1..10] ' –

+1

Ayrıca, aşağıdakileri de bir araya getirmek istediğiniz herhangi bir fonksiyon var: herhangi bir p = veya. harita p; hepsi p = ve. harita p; –

2

türe a -> Bool filtreleme işlevlerinin bir listesi varsa ve Bunları aynı türden tek özlü bir filtreleme işlevinde birleştirmek istiyoruz, sadece yapacak işlevleri yazabiliriz. Kullandığınız aşağıdaki iki işlevden hangisi, ihtiyacınız olan filtre davranışına bağlı olacaktır.

anyfilt :: [(a -> Bool)] -> (a -> Bool) 
anyfilt fns = \el -> any (\fn -> fn el) fns 

allfilt :: [(a -> Bool)] -> (a -> Bool) 
allfilt fns = \el -> all (\fn -> fn el) fns 

anyfilt filtre fonksiyonlarının tüm return false eğer filtre fonksiyonlarının herhangi doğru ve return false true dönecektir. Tüm filtre işlevleri true olursa allfilt, filtre işlevlerinden biri yanlış döndürürse yanlış döndürür. Her iki işlevi de RHS üzerindeki fns başvuruları anonim işlevler olarak η-azaltılamayacağınızı unutmayın.

böyle kullanın:

filterLines :: [String] -> [String] 
filterLines = let 
    isComment = isPrefixOf "# " 
    isBlank = (==) "" 
    badLine = anyfilt([isComment, isBlank]) 
    in filter (not . badLine) 

main = mapM_ putStrLn $ filterLines ["# comment", "", "true line"] 
--> "true line" 
İlgili konular