I am fairly new to Haskell and I would like to express the concept of and IO action that might or might not happen.
Network.URI provides a function to parse a URI
parseURI :: String -> Maybe URI
in my main function I get the input form the user
main :: IO ()
main = do
url <- getLine
getResource url
and the use the parseURI function
getResource :: String -> Maybe (IO ())
getResource url = parseURI url >>= doStuff
doStuff :: URI -> Maybe (IO ())
doStuff = undefined
As you can see I want to use >>= to avoid the case of cascade I would get dealing with the Maybes.
I have managed to do so by embedding IO into Maybe. I want to express the case of an IO action that may or may not happen. What should I use? I'm surely not the first one with this problem. I have looked into MaybeT and MonadIO but I am not sure that's what I need.
Specifically, if I move doStuff to MaybeT IO () I'm still stuck with parseURI url :: Maybe String. If I lift that to MaybeT now I have MaybeT Maybe String and that won't match my doStuff :: MaybeT IO ()
I'd like this to look better (if possible) and to understand what is the right direction and what are the mainstream tools to use.
Thank you for your time and advice.
First off: the type of an IO () action that may or may not happen can be simply IO (): you don't care about a result, or whether it was succesful, you just want it executed if possible.
If you do care about the success, then there are two options.
Maybe (IO ()) is the type of an action or not an action, but whether is a transparent “pure value”. I.e., if you have a Maybe (IO ()) value on the top-level, then you're able to determine if an action can happen without actually having to do any IO first. But this can not be the type of a value where you first have to do some IO to determine whether the critical action is going to happen, because in order to bind any IO you already have to be in the Just branch of the Maybe! So, if success depends on a user-supplied string then this can't be the right type for you.IO (Maybe ()) is the type of an IO action which may do anything it needs to determine what action to take. The type is actually equivalent to a IO Bool – an IO action returning some indicator flag. You may specify that Just () means some critical action has happened and Nothing means it hasn't, but there's no way to actually see this from the signature.MaybeT IO () is equivalent to the latter to, and is in fact probably the best type for you application. Only, you need to do the transformer-lifting correctly! lift takes an action from down in the transformer stack, up to the top of that stack. Hence lift! You need it for instance to lift a normal IO action like getLine :: IO String into the MaybeT IO stack:
lift getLine :: MaybeT IO String
But if you have a pure Maybe value, you rather need to “underpin” it to get a MaybeT IO. The easiest way to do that is to just use the MaybeT constructor directly.
getResource :: String -> MaybeT IO ()
getResource url = MaybeT (return $ parseURI url) >>= doStuff
doStuff :: URI -> MaybeT IO ()
doStuff = undefined
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With