2010-02-04 7 views
8

Ho bisogno combinatori binari del tipoQuesti due combinatori sono già disponibili in Haskell?

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

o forse

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

(anche se questo potrebbe essere solo la foldr1 del primo, e di solito solo bisogno di combinare due funzioni booleane.)

Questi sono integrati?


In caso contrario, l'implementazione è semplice:

both f g x = f x && g x 
either f g x = f x || g x 

o forse

allF fs x = foldr (\ f b -> b && f x) True fs 
anyF fs x = foldr (\ f b -> b || f x) False fs 

Hoogle salta fuori nulla, ma a volte la sua ricerca non generalizzare correttamente. Qualche idea se questi sono integrati? Possono essere costruiti da pezzi di una biblioteca esistente?

Se questi non sono integrati, è possibile suggerire nuovi nomi, perché questi nomi sono piuttosto negativi. In effetti, questo è il motivo principale per cui spero che abbiano integrato.

+0

'o :: (a -> c) -> (b -> c) -> O un b -> c' è già in' Prelude'; scegli un nome diverso? – ephemient

+0

Lo so, è per questo che speravo che qualcuno potesse suggerire delle belle alternative. –

risposta

13

Control.Monad definisce una instance Monad ((->) r), così

 
ghci> :m Control.Monad 
ghci> :t liftM2 (&&) 
liftM2 (&&) :: (Monad m) => m Bool -> m Bool -> m Bool 
ghci> liftM2 (&&) (5 <) (< 10) 8 
True 

Si potrebbe fare lo stesso con Control.Applicative.liftA2.


Non per suggerire sul serio, ma ...

 
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

Grazie, non sapevo di quell'istanza. Quindi non ho nemmeno provato 'liftM2 (&&)'. –

+2

@ephemient: che ne dici di 'fmap e. sequence'? – yairchu

+1

Penso che andrei con Monoid ('Any' e' All', in particolare) e 'mconcat'. – jrockway

1

Non conosco i build, ma mi piacciono i nomi che proponi.

getCoolNumbers = filter $ either even (< 42) 

In alternativa, si potrebbe pensare a un simbolo dell'operatore oltre alle maschere per alternative.

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

La ragione per cui non mi piace 'o' è a causa di' Prelude.either' aka 'Data.Either.either'. Oltre ad essere già usato, mi piacciono anche loro. :) –

+2

Informazioni sull'operatore: <&&> non è utilizzato e <||> solo da Parsec (secondo hoogle). Quindi quelli sono probabilmente le migliori alternative. –

6

Non è un incorporato, ma l'alternativa preferisco è quello di utilizzare le classi di tipo a generalizzare le operazioni booleane per predicati di qualsiasi A:

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) 

Amo Haskell!

+1

Ooh, bello, anche se i messaggi di errore se si mischiano mai accidentalmente le strutture potrebbero essere * interessanti *. In realtà mi prendo cura di chiamare questi '. &&. .||. 'o qualcosa del genere :-) – ephemient

+0

Questo è davvero bello. Sono contento di esserci imbattuto in questo! Haskell non smette mai di stupire: D –