Как объединить условия фильтра
Класс фильтров функций принимает условие (a → Bool) и применяет его при фильтрации.
Каков наилучший способ использования фильтра при наличии нескольких условий?
Используется аппликативная функция
liftA2 вместо liftM2, потому что я почему-то не понял, как liftM2 работал в чистом коде.
Ответы
Ответ 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"