I'm working with the servant library for an API. It runs in the: EitherT (Int, String) IO a monad. I have a function with the type IO Maybe a, and would like to use it.
Here's an example that works:
sourcesGetAll :: EitherT (Int, String) IO [Source]
sourcesGetAll = liftIO $ sourcesList h
sourcesList :: IO [Source]
But now I want to use these two functions together
sourcesFind :: IO (Maybe Source)
sourcesGetOne :: EitherT (Int, String) IO Source
sourcesGetOne = ???
I would like to do this:
maybeNotFound :: Maybe a -> Either (Int, String) a
maybeNotFound Nothing = Left (404, "Not Found")
maybeNotFound Just a = Right a
How do I do that with all the fancy monads?
You can use hoistEither :: Monad m => Either a b -> EitherT a m b to implement this:
maybeNotFoundT :: IO (Maybe a) -> EitherT (Int, String) IO a
maybeNotFoundT maAct = do
ma <- liftIO maAct -- get the Maybe a. Now ma :: Maybe a
hoistEither $ maybeNotFound ma
You can decompose this into two separate problems:
Transform IO (Maybe a) into MaybeT IO a
Transform MaybeT IO a into EitherT (Int, String) a
The first one is solved by using the MaybeT constructor:
MaybeT :: IO (Maybe a) -> MaybeT IO a
The second is solved by using noteT from the errors library:
noteT :: Monad m => a -> MaybeT m b -> EitherT a m b
Another answer thanks to mpickering on freenode:
sourcesGetOne = EitherT $ maybeNotFound <$> sourcesFind
So the question is how to write a function.. IO (Maybe a) -> EitherT (Int, String) IO a
Given a function f :: Maybe a -> Either (Int, String) a, then one way is..
myFunc action = EitherT (f <$> action)
If you look at the docs for EitherT -- https://hackage.haskell.org/package/either-4.3.3.2/docs/Control-Monad-Trans-Either.html. Then you'll see that EitherT (Int, String) IO a, is actually just a wrapped up IO (Either (Int, String) a)
Related
I have a function that requires the handling of two Maybes. This is an extremely naive implementation:
go :: IO (Maybe Int)
go = do
res1 <- firstFunction
case res1 of
Nothing -> return Nothing
Just a -> do
res2 <- secondFunction a
case res2 of
Nothing -> return Nothing
Just b -> return b
How could I structure this so that I can use the result a of the firstFunction in my secondFunction?
Use MaybeT IO a instead of IO (Maybe a). Then:
firstFunction :: MaybeT IO X
firstFunction = undefined -- ...
secondFunction :: X -> MaybeT IO Int
secondFunction = undefined -- ...
go :: IO (Maybe Int)
go = do
a <- firstFunction
secondFunction a
-- OR
go = firstFunction >>= secondFunction
You may use these two halves of an isomorphism to convert between the two types:
MaybeT :: IO (Maybe a) -> MaybeT IO a
runMaybeT :: MaybeT IO a -> IO (Maybe a)
To reduce the total number of uses of them, I recommend pushing the former as deep into the leaves of your computation as you can, and lifting the latter as far out as you can. You may also like these actions for defining leaf computations:
lift :: IO a -> MaybeT IO a
liftIO :: IO a -> MaybeT IO a
empty :: MaybeT IO a -- for when you want a Nothing
pure :: a -> MaybeT IO a -- for when you want a Just
maybe empty pure :: Maybe a -> MaybeT IO a
I met this question today while learning haskell monad transformers.
Assume I have a type instance Monad m => Monad (CustomT m).
If there's a function f :: CustomT IO Int, and there's g :: IO (Maybe Int).
How do I access the Int of g in f?
I tried something like
f = do
mVal <- g
This didn't work because f is under CustomT IO monad while g is under MaybeT IO monad.
And then I tried
f = do
mVal <- return g
This seems to work but mVal is IO (Maybe Int) type, I eventually get nested IO like CustomT IO (IO something)
Is there a way to get that Int or Maybe Int out in f?
What knowledge is involved?
Thanks in advance.
In the general case, Jeremy's answer is what you want. But let's see if we can work with your specific case here. We have f :: CustomT IO Int and g :: IO (Maybe Int), given that there exist some instances to the effect of instance Monad m => Monad (CustomT m) and instance MonadTrans CustomT.
And what you want is to get at the Int inside of a g within the context of CustomT IO. Since we're inside of CustomT, we can basically strip that layer off trivially. Like Jeremy says, use lift to get rid of that.
lift :: (MonadTrans t, Monad m) => m a -> t m a
So now we have CustomT IO (Maybe Int). Like I said, we're inside a do-block, so using Haskell's bind (<-) syntax gets rid of the monad layer temporarily. Thus, we're dealing with Maybe Int. To get from Maybe Int to Int, the usual approach is to use maybe
maybe :: b -> (a -> b) -> Maybe a -> b
This provides a default value just in case the Maybe Int is actually Nothing. So, for instance, maybe 0 id is a function that takes a Maybe Int and yields the inner Int, or 0 if the value is Nothing. So, in the end, we have:
f = do
mVal <- maybe 0 id $ lift g
-- Other code
In the Control.Monad.Trans you have this definition for monad transformers:
class MonadTrans (t :: (* -> *) -> * -> *) where
lift :: Monad m => m a -> t m a
Which means that if CustomT has been defined properly you can do this:
f = do
mVal <- lift g
I have this code:
trick = Just (putStrLn "Hello?")
And I want to unwrap this IO () out the Maybe context and call it.
main = do foo <- trick
foo
However, this throws an error:
Couldn't match type ‘IO’ with ‘Maybe’
Expected type: Maybe ()
Actual type: IO ()
How could I resolve this?
The function you are looking for is Data.Foldable.sequence_:
>>> Data.Foldable.sequence_ (Just (putStrLn "Hello?"))
Hello?
>>>
If your Maybe is Nothing, it will not do anything:
>>> Data.Foldable.sequence_ Nothing
>>>
This works because the type of Data.Foldable.sequence_ is:
Data.Foldable.sequence_
:: (Foldable t, Monad m) => t (m a) -> m ()
... and if you specialize t to Maybe and m to IO, you get:
Data.Foldable.sequence_ :: Maybe (IO a) -> IO ()
In the specific context of Maybe, it's equivalent to:
sequence_ (Just io) = do
_ <- io
return ()
sequence Nothing = return ()
The easiest solution to start out with is probably to realize that you can decide what to do based on the value of the Maybe (IO ()) via pattern matching.
maybeDoIO :: Maybe (IO ()) -> IO ()
maybeDoIO (Just io) = io
maybeDoIO Nothing = return ()
You have to take the Nothing into account, basically:
main = maybe (putStrLn "Nothing") id foo
The problem with your main function is that you are mixing two different monads in the same do block.
The foo <- trick action is "relative" to the Maybe monad but the foo action afterwards is an IO action. The type for >>= is:
Monad m => m a -> (a -> m b) -> m b
But in your case you'd need something with type:
Maybe a -> (a -> IO b) -> IO b
with two different monads.
If you want to execute the IO action then the type of main must be of the kind IO a so the do notation must refer to IO and not Maybe. Which means that you cannot use <- to extract the action but you have to use something else. For example Data.Maybe.fromMaybe:
import Data.Maybe
main = do fromMaybe (return ()) trick
Working in an IO computation I ended up with a staircase of case mbValue of …s and figured out that I should use the Maybe monad to simplify the code. Since it's within an IO computation and I need to get IO values, I used the MaybeT monad transformer so that I can lift IO computation into Maybe.
Now, I have always thought about values being “stripped” of their Maybeness after an values <- mbValue inside a Maybe computation, but this turns out to be too simple of a heuristic here.
As highlighted below, when using a Maybe a value as an a (here by passing it to read), it fails to type check:
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT)
lol :: IO (Maybe Int)
lol = return (Just 3)
lal :: IO (Maybe String)
lal = return (Just "8")
foo :: IO (Maybe Bool)
foo = do
b <- runMaybeT $ do
x <- lift lol
y <- lift lal
return (x < (read y))
return b ^-- Couldn't match type ‘Maybe String’ with ‘String’
main = foo >>= print
If I put a typed hole in for return (x < (read y)), I see that it expects a Bool, which makes sense, but also that the current bindings include
|| y :: Data.Maybe.Maybe GHC.Base.String
|| (bound at /private/tmp/test.hs:14:5)
|| x :: Data.Maybe.Maybe GHC.Types.Int
|| (bound at /private/tmp/test.hs:13:5)
I.e., y is a Maybe String. This of course explains the error, but I'm left confused. Where is my understanding wrong, and how can I fix this error?
In short: Replace lift by the MaybeT constructor.
Note that
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
and
lift :: (MonadTrans t, Monad m) => m a -> t m a
Your use of lift in
x <- lift lol
is at the type
lift :: IO (Maybe Int) -> MaybeT IO (Maybe Int)
That's why x will be a Maybe Int again. The lift adds a fresh MaybeT layer that is independent of the Maybe occurrence you already have.
But
MaybeT :: m (Maybe a) -> MaybeT m a
instead as in
x <- MaybeT lol
will be used at type
MaybeT :: IO (Maybe a) -> MaybeT IO a
and do the right thing.
When specialized to MaybeT, lift :: Monad m => m a -> MaybeT m a. Since lol :: IO (Maybe Int), m is IO and a is Maybe Int, therefore lift lol :: MaybeT IO (Maybe Int).
IO (Maybe a) is just the value contained within a MaybeT IO a newtype wrapper, so there's no need to lift it; instead use the MaybeT constructor, for example as in MaybeT lol.
But this is not how people tend to use monad transformers. Instead, just use MaybeT values and lift as needed:
import Control.Monad
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT, MaybeT)
lol :: MaybeT IO Int
lol = return 3
lal :: MaybeT IO String
lal = return "8"
foo :: IO (Maybe Bool)
foo =
runMaybeT $ do
x <- lol
y <- lal
_ <- lift getLine -- lift (IO String) to MaybeT IO String
_ <- return 100 -- lift any pure value
_ <- mzero -- use the MonadPlus instance to get a lifted Nothing.
return (x < (read y))
main = foo >>= print
Why does this function have the type:
deleteAllMp4sExcluding :: [Char] -> IO (IO ())
instead of deleteAllMp4sExcluding :: [Char] -> IO ()
Also, how could I rewrite this so that it would have a simpler definition?
Here is the function definition:
import System.FilePath.Glob
import qualified Data.String.Utils as S
deleteAllMp4sExcluding videoFileName =
let dirGlob = globDir [compile "*"] "."
f = filter (\s -> S.endswith ".mp4" s && (/=) videoFileName s) . head . fst
lst = f <$> dirGlob
in mapM_ removeFile <$> lst
<$> when applied to IOs has type (a -> b) -> IO a -> IO b. So since mapM_ removeFile has type [FilePath] -> IO (), b in this case is IO (), so the result type becomes IO (IO ()).
To avoid nesting like this, you should not use <$> when the function you're trying to apply produces an IO value. Rather you should use >>= or, if you don't want to change the order of the operands, =<<.
Riffing on sepp2k's answer, this is an excellent example to show the difference between Functor and Monad.
The standard Haskell definition of Monad goes something like this (simplified):
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
However, this is not the only way the class could have been defined. An alternative runs like this:
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
Given that, you can define >>= in terms of fmap and join:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (f <$> ma)
We'll look at this in a simplified sketch of the problem you're running into. What you're doing can be schematized like this:
ma :: IO a
f :: a -> IO b
f <$> ma :: IO (IO b)
Now you're stuck because you need an IO b, and the Functor class has no operation that will get you there from IO (IO b). The only way to get where you want is to dip into Monad, and the join operation is precisely what solves it:
join (f <$> ma) :: IO b
But by the join/<$> definition of >>=, this is the same as:
ma >>= f :: IO a
Note that the Control.Monad library comes with a version of join (written in terms of return and (>>=)); you could put that in your function to get the result you want. But the better thing to do is to recognize that what you're trying to do is fundamentally monadic, and thus that <$> is not the right tool for the job. You're feeding the result of one action to another; that intrinsically requires you to use Monad.