I am trying to stack up IO and Maybe monads but either I don't understand monad transformers well enough or this is not possible using transformers. Can some one help me understand this?
f :: String -> Maybe String
main :: IO ()
main = do
input <- getLine -- IO String
output <- f input -- Maybe String (Can't extract because it is IO do block)
writeFile "out.txt" output -- gives error because writeFile expects output :: String
In the above simplified example, I have a function f
that returns a Maybe String
and I would like to have a neat way of extracting this in the IO
do block. I tried
f :: String -> MaybeT IO String
main :: IO ()
main = do
input <- getLine -- IO String
output <- runMaybeT (f input) -- Extracts output :: Maybe String instead of String
writeFile "out.txt" output -- gives error because writeFile expects output :: String
which lets me extract the Maybe String
out in the second line of do
block but I need to extract the string out of that. Is there a way to do this without using case
?
Let's stick for a moment with your first snippet. If f input
is a Maybe String
, and you want to pass its result to writeFile "out.txt"
, which takes a String
, you need to deal with the possibility of f input
being Nothing
. You don't have to literally use a case-statement. For instance:
maybe
from the Prelude is case analysis packaged as a function;
fromMaybe
from Data.Maybe
lets you easily supply a default value, if that makes sense for your use case;
traverse_
and for_
from Data.Foldable
could be used to silently ignore Nothing
-ness:
for_ (f input) (writeFile "out.txt") -- Does nothing if `f input` is `Nothing`.
Still, no matter what you choose to do, it will involve handling Nothing
somehow.
As for MaybeT
, you don't really want monad transformers here. MaybeT IO
is for when you want something like a Maybe
computation but in which you can also include IO
computations. If f :: String -> Maybe String
already does what you want, you don't need to add an underlying IO
layer to it.