私は1つができることを知っています:
any (>3) [1,2,3,4,5]
しかし、実装のエレガントな方法は何ですか:
any and[(>3),(<5)] [1,2,3,4,5]
また
all or[(<2),(>4)] [1,2,3,4,5]
等?
私は1つができることを知っています:
any (>3) [1,2,3,4,5]
しかし、実装のエレガントな方法は何ですか:
any and[(>3),(<5)] [1,2,3,4,5]
また
all or[(<2),(>4)] [1,2,3,4,5]
等?
(<5)
との両方の要素があるかどうかを確認したいと思います(>3)
。
あなたはこのようにそれを行うことができます:
any (\x -> x > 3 && x < 5) [1..5]
そしてあなたの他の1つはによって行うことができます
any (\x -> x < 2 || x > 4) [1..5]
しかし、関数を定義&&
して作業する方が楽しいかもしれません。||
infixr 3 &&&
infixr 3 |||
(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(f &&& g) x = f x && g x
(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(f ||| g) x = f x || g x
これで、例を次のように書き直すことができます。
any ((>3) &&& (<5)) [1..5]
any ((<2) ||| (>4)) [1..5]
表記and[(>3),(<5)]
は、高階関数としてほぼ直接実装できます。述語と値のリストを取り、述語のリストを受け取る関数が必要なのでandP
、これを呼び出します。any
andP :: [a -> Bool] -> a -> Bool
andP ps x = all ($ x) ps
今
andP [(>3), (<5)] x = x > 3 && x < 5
そして、あなたはあなたの最初の要求のように書くことができます
any (andP [(>3), (<5)]) [1,2,3,4,5]
ちなみに、この特定の例では、より明確な方法は次のようになると思います。
between :: (Ord a) => a -> a -> a -> Bool
between lo hi x = lo < x && x < hi
any (between 3 5) [1,2,3,4,5]
別のアプローチは、を使用することMonoid
です。でまたはからラップされBool
たときです。組み合わせるには2つの方法があるため、これが必要です。またはを使用できます。そのため、のタイプとインスタンスがあります。例えば:Monoid
All
Any
Data.Monoid
[Bool]
&&
||
All :: Bool -> All
Any :: Bool -> Any
Monoid
> import Data.Monoid
> getAll $ mconcat [All True, All True, All False]
False
> getAll $ mconcat [All True, All True, All True]
True
> getAny $ mconcat [Any True, Any True, Any False]
True
私たちが使用するもう1つの事実は、Monoid
関数のインスタンスです(ここでもData.Monoid
):
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
これで、関数を追加できます。
> :t All
All :: Bool -> All
> :t (<5)
(<5) :: (Num a, Ord a) => a -> Bool
> :t All . (<5)
All . (<5) :: (Num a, Ord a) => a -> All
> :t ((All . (<5)) <> (All . (>3)))
((All . (<5)) <> (All . (>3))) :: (Num a, Ord a) => a -> All
> getAll $ ((All . (<5)) <> (All . (>3))) 4
True
これを関数のリストに一般化する:
> getAll $ mconcat [(All. (<5)), (All . (>3))] $ 4
True
> getAll $ mconcat (map (All .) [(<5), (>3)]) $ 4
True
次に、 http://www.haskell.org/hoogle/を検索して、次の代わりに使用できるものを(a->b) -> [a] -> b
確認します。foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
mconcat . map
> import Data.Foldable
> getAll $ foldMap (All .) [(<5), (>3)] $ 4
True
そして最後にそれを数字のリストにマッピングします:
> map (getAll . foldMap (All .) [(<5), (>3)]) $ [1..5]
[False,False,False,True,False]
> Prelude.or $ map (getAll . foldMap (All .) [(<5), (>3)]) $ [1..5]
True
Monoid
次のようにいくつかのインスタンスを使用して、述語のリストを取得する演算子を定義することもできます。
test = any (andP [(>3),(<5)]) [1,2,3,4,5]
andP :: [a -> Bool] -> a -> Bool
andP ps = getAll . mconcat (map (All.) ps)