2015-12-04 8 views
8

Ho un paio di frammenti che sembrano voler fare la stessa cosa, ma non sono del tutto convinto che ci sia un costrutto generalizzato per gestirli entrambi . In un unico luogo, hoCercare la generalizzazione del costrutto `se px then x else empty`

ensure :: (String -> Bool) -> String -> String 
ensure p x = 
    if p x then 
     x 
    else 
     "" 

Questo potrebbe in uso aspetto qualcosa come

ensure (/= "kim") "alex" -- returns "alex" 
ensure (/= "kim") "kim"  -- returns "" 

in un altro, ho il molto simile

ensure :: (a -> Bool) -> Maybe a -> Maybe a 
ensure p maybeX = do 
    x <- maybeX 
    if p x then 
     Just x 
    else 
     Nothing 

Questo sarebbe invece un aspetto simile

ensure even 6  -- returns Just 6 
ensure even 11 -- returns Nothing 

Entrambi sono cking se un valore è corretto secondo alcuni predicati, e se non lo è restituiscono un valore "vuoto" predefinito. C'è una leggera differenza anche se - il che significa che la seconda funzione potrebbe essere riscritta come

ensure :: (Maybe a -> Bool) -> Maybe a -> Maybe a 
ensure p maybeX = 
    if p x then 
     x 
    else 
     Nothing 

per renderli più simili, mettendo la responsabilità di "scartare" la Maybe sul predicato. Con questa nuova definizione, entrambe le funzioni cadrebbero sotto

ensure :: Alternative f => (f a -> Bool) -> f a -> f a 
ensure p x = 
    bool x empty (p x) 

Quindi, la mia domanda è,

Fa questo bool x empty (p x) esistono in qualche forma, quindi non c'è bisogno di implementare questa funzione me stesso? Il problema con inlining bool x empty (p x) è che nel mio caso, sia p sia x sono piuttosto lunghi.

+4

definirei 'ensure' come' assicurare :: MonadPlus m => (a -> bool) -> a -> M a; assicurare p = mfilter p. return'. – user3237465

+6

'ensure' mi ricorda [' guard'] (http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:guard) ma sembra molto più utile – Bergi

+0

il secondo modulo sembra ['mfilter'] (http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:mfilter). Passare un valore da scartare al predicato sembra essere migliore. – Bergi

risposta

1

Ci sono stati due suggerimenti. Un utilizzando Monoide:

ensure :: Monoid a => (a -> Bool) -> a -> a 
ensure p a = if p a then a else mempty 

E un altro utilizzando MonadPlus:

ensure :: MonadPlus m => (a -> Bool) -> a -> m a 
ensure p = mfilter p . return 
Problemi correlati