18

In particolare, devo essere in grado di combinare il monad CGI con la monade IO, ma un esempio di come combinare la monade IO con la Forse monad potrebbe essere ancora meglio ...Come si combinano le monadi in Haskell?

+0

letture interessanti: [Monad_transformers] (http://www.haskell.org/haskellwiki/Typeclassopedia#Monad_transformers) – mb21

risposta

0

In che senso vuoi combinare le monadi?

f :: Int -> IO (Maybe Int) 
f x = do 
    putStrLn "Hello world!" 
    return $ if x == 0 then Nothing else Just x 

può essere valutata a:

[1 of 1] Compiling Main    (maybe-io.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> f 0 
Hello world! 
Nothing 
*Main> f 3 
Hello world! 
Just 3 
+3

Non stai componendo calcoli su Forse, e quindi il fatto che Forse è una monade è irrilevante. – jrockway

17

Non è esattamente dire come si desidera combinare IO e Maybe, ma suppongo che hai molte funzioni che restituiscono IO (Maybe a) che si desidera combinare con facilità . In sostanza si vuole trattare IO (Maybe a) come un tipo separato con un proprio Monad esempio:

newtype IOMaybe a = IOM (IO (Maybe a)) 

-- "unpack" a value of the new type 
runIOMaybe :: IOMaybe a -> IO (Maybe a) 
runIOMaybe (IOM a) = a 

instance Monad IOMaybe where 
    -- bind operator 
    (IOM ioa) >>= f = IOM $ do 
     a <- ioa 
     case a of 
     Nothing -> return Nothing 
     Just v -> runIOMaybe (f v) 

    -- return 
    return a = IOM (return (Just a)) 

-- maybe also some convenience functions 
returnIO :: IO a -> IOMaybe a 
returnIO ioa = IOM $ do 
    v <- ioa 
    return (Just v) 

returnMaybe :: Maybe a -> IOMaybe a 
returnMaybe ma = IOM (return ma) 

Con questo si può utilizzare il do -Notation di combinare funzioni che restituiscono IO (Maybe a), IO a o Maybe a:

f1 :: Int -> IO (Maybe Int) 
f1 0 = return Nothing 
f1 a = return (Just a) 

main = runIOMaybe $ do 
    returnIO $ putStrLn "Hello" 
    a <- returnMaybe $ Just 2 
    IOM $ f1 a 
    return() 

Generalmente qualcosa che combina e modifica le monadi come questa si chiama monad transformer, e GHC viene fornito con un package che include i trasformatori monad per casi comuni. Se c'è qualcosa in questa libreria di trasformatori monad che si adatta al tuo scenario dipende da come esattamente vuoi combinare Maybe e IO.

+0

Se non lo sapessi, puoi creare automaticamente 'runIOMaybe' dichiarando' newtype IOMaybe a = IOM {runIOMaybe :: IO (Maybe a)} ' – rovaughn

21

Presumo che si desideri utilizzare la funzione Forse monad per la terminazione anticipata (ad esempio break o return in C).

In tal caso, è necessario utilizzare MaybeT dal pacchetto MaybeT (cabal install MaybeT).

main = do 
    runMaybeT . forever $ do 
    liftIO $ putStrLn "I won't stop until you type pretty please" 
    line <- liftIO getLine 
    when ("pretty please" == line) mzero 
    return() 

MaybeT è una versione monad di trasformatore della forse monade.

I trasformatori Monad "aggiungono funzionalità" ad altre monadi.

+3

Inoltre non vale niente che ci sia ErrorT in mtl, e che anche implementa MonadPlus, il che significa che il codice sopra funzionerà quasi invariato nella monade Error. (Il cambiamento è che la parte "Left" di ErrorT ha bisogno di una firma di tipo, poiché "mzero" non è abbastanza specifico.) – jrockway

+0

@jrockway: E il tipo di sinistra avrebbe bisogno di un'istanza di 'Error', che è un po 'scomoda perché 'MaybeT' è in realtà isomorfo a qualcosa come' ErrorT() ', ma questo non è permesso poiché non c'è' instance Error() '. Meglio usare 'EitherT', ma questo richiede anche un pacchetto aggiuntivo. –