2012-10-26 9 views
5

Cerco un modo idiomatico di fareApplicare una funzione solo se isJust

moveMaybeCreature Nothing world = world 
moveMaybeCreature (Just creature) world = moveCreature creature world 

O in altre parole

if isJust c 
    then doSomething (fromJust c) w 
    else w 

ho pensato che potevo a questo modo:

moveMaybeCreature c w = foldr moveCreature w (maybeToList c) 

Posso farlo senza dover convertire Maybe Creature a [Creature]?

risposta

10

È possibile eseguire questa operazione finché il tipo di world e moveCreature (fromJust c) world è lo stesso. È possibile utilizzare maybe da Data.Maybe.

moveMaybeCreature = maybe id moveCreature 

Il tuo primo modo di fare il modello coincidenze dovrebbe funzionare anche bene.

+1

Questa è la prima funzione descritta nel documento per Data. Forse, e in qualche modo l'ho persa. Grazie! – Niriel

+0

Come nota a margine, c'è anche l'equivalente per 'Either':' o' in 'Data.Either'. – David

+1

La tua precondizione sui tipi è praticamente garantita se 'moveMaybeCreature' ha un controllo di tipo in primo luogo ... –

5

Io secondo la raccomandazione di utilizzare la funzione maybe. Hai ragione a porre questa domanda a causa di questa regola generale (non solo per te, ma per i nuovi arrivati ​​che la leggono): funzioni con tipi come Maybe Foo -> Bar o Maybe Foo -> Maybe Bar che sono definiti direttamente sono code smell in Haskell. Non vuoi quasi mai scrivere una funzione che consideri Maybe Foo come argomento; si desidera una funzione che richiede solo Foo e utilizzare una funzione di ordine superiore per adattarla a Maybe Foo.

Supponiamo di avere una funzione f' :: Maybe Foo -> Maybe Bar. Questo di solito può essere riscritta in uno:

  1. f :: Foo -> Bar e fmap f :: Maybe Foo -> Maybe Bar;
  2. f :: Foo -> Maybe Bar e (>>=f) :: Maybe Foo -> Maybe Bar

Primo caso funziona, perché questo è l'istanza Functor per Maybe:

instance Functor Maybe where 
    fmap f Nothing = Nothing 
    fmap f (Just x) = Just (f x) 

-- or this: 
--  fmap f = maybe Nothing (Just . f) 

Secondo caso funziona perché questo è l'istanza Monad per Maybe:

instance Monad Maybe where 
    return = Just 
    Nothing >>= f = Nothing 
    (Just x) >>= f = f x 

-- or this: 
--  mx >>= f = maybe Nothing f mx 
+0

.... e come diceva Satvik, se hai una funzione di tipo 'Maybe a -> b' come la tua, puoi usare la funzione' maybe' per rifattarla. – AndrewC

+1

È interessante notare che se stai scrivendo una funzione come 'forse :: a -> b -> Forse c -> Forse d -> Forse e -> Forse f', puoi usare Applicative e scrivere il bit puro assumendo tutto il forse i dati sono disponibili e definiscono 'maybe = purebit ab <$> c <*> d <*> e'. – AndrewC

3

Ecco un altro opt ione, più vicino al tuo codice originale:

import qualified Data.Foldable as F 

moveMaybeCreature = flip (F.foldr moveCreature) 
Problemi correlati