Вы точно не говорите, как вы хотите объединить IO
и Maybe
, но я предполагаю, что у вас есть много функций, которые возвращают IO (Maybe a)
, которые вы хотите легко объединить. В основном вы хотите рассматривать IO (Maybe a)
как отдельный тип со своим собственным Monad
экземпляром:
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)
При этом вы можете использовать do
-Notation для объединения функций, которые возвращают IO (Maybe a)
, IO a
или 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 ()
Обычно то, что объединяет и модифицирует монады, как это, называется преобразователь монад , и GHC поставляется с пакетом , который включает в себя преобразователи монад для общих случаев. Если в этой библиотеке монадных преобразователей есть что-то, что подходит для вашего сценария, зависит от того, как именно вы хотите объединить Maybe и IO.