2010-02-04 2 views
8

мне нужно двоичные комбинаторов типаЭти два комбинатора уже доступны в Haskell?

(a -> Bool) -> (a -> Bool) -> a -> Bool 

или, может быть,

[a -> Bool] -> a -> Bool 

(хотя это было бы просто быть foldr1 из первых, и я обычно нужно только объединить две булевы функции.)

Являются ли эти встроенные?


Если нет, то реализация проста:

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 поворачивает вверх ничего, но иногда его поиск не обобщать должным образом. Любая идея, если они встроены? Могут ли они быть построены из частей существующей библиотеки?

Если они не встроены, вы можете предлагать новые имена, потому что эти имена довольно плохи. На самом деле, это главная причина, я надеюсь, что они являются встроенный.

+0

'or :: (a -> c) -> (b -> c) -> Либо b -> c' уже находится в' Prelude'; выбрать другое имя? – ephemient

+0

Я знаю, поэтому я надеялся, что кто-то может предложить хорошие альтернативы. –

ответ

13

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 
+0

Спасибо, я не знал об этом случае. Поэтому я даже не попробовал 'liftM2 (&&)'. –

+2

@ephemient: как насчет 'fmap и. sequence'? – yairchu

+1

Думаю, я поеду с Monoid ('Any' и' All', в частности) и 'mconcat'. – jrockway

1

Я не знаю встроенных, но мне нравятся имена, которые вы предлагаете.

getCoolNumbers = filter $ either even (< 42) 

В качестве альтернативы можно было бы использовать символ оператора в дополнение к классам для альтернатив.

getCoolNumbers = filter $ even <|> (< 42) 
+1

Причина, по которой мне не нравится '' ', - это из-за' Prelude.either' aka 'Data.Either.either'. Кроме того, я уже их использую. :) –

+2

Об операторе: <&&> не используется и <||> только Parsec (согласно hoogle). Так что это, вероятно, лучшие альтернативы. –

6

Это не является встроенным, но альтернативой Я предпочитаю использовать классы типа для обобщать булевы операции предикатов любого arty:

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) 

Я люблю Haskell!

+1

О, хорошо, хотя сообщения об ошибках, если вы когда-либо случайно смешаете арты, могут быть интересными *. Я бы предпочел называть эти '. &&. . || .' или что-то в этом роде :-) – ephemient

+0

Это действительно круто. Рад, что я наткнулся на это! Хаскелл никогда не перестает удивлять: D –