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?
risposta
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
Non stai componendo calcoli su Forse, e quindi il fatto che Forse è una monade è irrilevante. – jrockway
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.
Se non lo sapessi, puoi creare automaticamente 'runIOMaybe' dichiarando' newtype IOMaybe a = IOM {runIOMaybe :: IO (Maybe a)} ' – rovaughn
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.
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
@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. –
letture interessanti: [Monad_transformers] (http://www.haskell.org/haskellwiki/Typeclassopedia#Monad_transformers) – mb21