Подтвердить что ты не робот

Как объединить условия фильтра

Класс фильтров функций принимает условие (a → Bool) и применяет его при фильтрации.

Каков наилучший способ использования фильтра при наличии нескольких условий?

Используется аппликативная функция liftA2 вместо liftM2, потому что я почему-то не понял, как liftM2 работал в чистом коде.

4b9b3361

Ответ 1

Комбинатор liftM2 может использоваться в монаде Reader, чтобы сделать это более "функциональным" способом:

import Control.Monad
import Control.Monad.Reader

-- ....

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

Обратите внимание, что импорт важен; Control.Monad.Reader предоставляет экземпляр Monad (e → ), который заставляет все это работать.

Причина этого в том, что монада-читатель является просто (e → ) для некоторой среды e. Таким образом, булевский предикат является 0-аричной монадической функцией, возвращающей bool в среде, соответствующей ее аргументу. Затем мы можем использовать liftM2 для распределения среды по двум таким предикатам.

Или, проще говоря, liftM2 будет действовать так же, как это происходит при разработке типов:

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

Вы также можете определить новый комбинатор, если хотите, чтобы вы могли легко их сцепить, и/или не хотите путаться с лифтомM2:

(.&&.) :: (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]

Ответ 2

Ну, вы можете комбинировать функции, которые вы хотите в Haskell (до тех пор, пока типы верны), и используя lambdas, вам даже не нужно называть вашу предикатную функцию, то есть

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

Ответ 3

Скажем, ваши условия хранятся в списке под названием conditions. Этот список имеет тип [a -> Bool].

Чтобы применить все условия к значению x, вы можете использовать map:

map ($ x) conditions

Это условие применяет каждое условие к x и возвращает список Bool. Чтобы уменьшить этот список до одного логического значения, True, если все элементы True, а False в противном случае, вы можете использовать функцию and:

and $ map ($ x) conditions

Теперь у вас есть функция, которая объединяет все условия. Пусть дайте ему имя:

combined_condition x = and $ map ($ x) conditions

Эта функция имеет тип a -> Bool, поэтому мы можем использовать ее при вызове filter:

filter combined_condition [1..10]

Ответ 4

Если у вас есть список фильтрующих функций типа a -> Bool и вы хотите объединить их в одну сжатую функцию фильтрации того же типа, мы можем написать функции, которые нужно сделать. Какая из двух функций ниже, которую вы используете, будет зависеть от вашего поведения фильтра.

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 вернет true, если какая-либо из функций фильтра вернет true и false, если все функции фильтра возвращают false. allfilt вернет true, если все функции фильтра возвращают true и false, если какая-либо из функций фильтра возвращает false. Обратите внимание, что вы не можете n-уменьшить любую функцию, поскольку ссылки на fns на RHS находятся в анонимных функциях.

Используйте его следующим образом:

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"