Эти два комбинатора уже доступны в Haskell?
-
18-09-2019 - |
Вопрос
Мне нужны бинарные комбинаторы типа
(a -> Bool) -> (a -> Bool) -> a -> Bool
или, может быть
[a -> Bool] -> a -> Bool
(хотя это будет просто первая папка, и мне обычно нужно объединить только две логические функции.)
Они встроенные?
Если нет, то реализация проста:
both f g x = f x && g x
either f g x = f x || g x
или возможно
allF fs x = foldr (\ f b -> b && f x) True fs
anyF fs x = foldr (\ f b -> b || f x) False fs
Hoogle ничего не выдает, но иногда его поиск не дает должных результатов.Есть идеи, встроены ли они?Могут ли они быть построены из частей существующей библиотеки?
Если они не встроены, вы можете предложить новые имена, потому что эти имена довольно плохие.На самом деле это главная причина, по которой я надеюсь, что они являются встроенный.
Решение
Control.Monad
определяет instance Monad ((->) r)
, так
ghci> :m Control.Monad ghci> :t liftM2 (&&) liftM2 (&&) :: (Monad m) => m Bool -> m Bool -> m Bool ghci> liftM2 (&&) (5 <) (< 10) 8 True
Вы могли бы сделать то же самое с Control.Applicative.liftA2
.
Не хочу серьезно это предлагать, но...
ghci> :t (. flip ($)) . flip all (. flip ($)) . flip all :: [a -> Bool] -> a -> Bool ghci> :t (. flip ($)) . flip any (. flip ($)) . flip any :: [a -> Bool] -> a -> Bool
Другие советы
Это не встроенная функция, но я предпочитаю использовать классы типов для обобщать логические операции до предикатов любого богатства:
module Pred2 where
class Predicate a where
complement :: a -> a
disjoin :: a -> a -> a
conjoin :: a -> a -> a
instance Predicate Bool where
complement = not
disjoin = (||)
conjoin = (&&)
instance (Predicate b) => Predicate (a -> b) where
complement = (complement .)
disjoin f g x = f x `disjoin` g x
conjoin f g x = f x `conjoin` g x
-- examples:
ge :: Ord a => a -> a -> Bool
ge = complement (<)
pos = (>0)
nonzero = pos `disjoin` (pos . negate)
zero = complement pos `conjoin` complement (pos . negate)
Я люблю Хаскель!
Я не знаю встроенных функций, но мне нравятся предлагаемые вами имена.
getCoolNumbers = filter $ either even (< 42)
В качестве альтернативы можно подумать о символе оператора в дополнение к классам типов для альтернатив.
getCoolNumbers = filter $ even <|> (< 42)