Inside a do block of a ExceptT String IO ()
I have a function that produces a ReaderT like so:
type UDCEnv = (AWS.Env, Bool)
uploadVersionFilesToCaches :: S3.BucketName
-> FilePath
-> [GitRepoNameAndVersion]
-> ReaderT UDCEnv IO ()
I just so happen to have a Maybe FilePath
so I create my ReaderT like so:
let maybeReader :: Maybe (ReaderT UDCEnv IO ()) =
uploadVersionFilesToCaches s3BucketName <$> maybeFilePath <*> Just gitRepoNamesAndVersions
I can even run the ReaderT like so:
let maybeIO :: Maybe (IO ()) =
runReaderT <$> maybeReader <*> Just (env, shouldIgnoreLocalCache, verbose)
Everything works fine as long as I use let
expressions. As soon as I drop the let
in the expression above to actually try to have expression evaluated Applicative gets types as ExceptT String IO FilePath
instead of Maybe
The parts I am omitting are marked by ...
:
f :: ... -> ExceptT String IO ()
f ... = do
...
runReaderT <$> maybeReader <*> Just (env, shouldIgnoreLocalCache, verbose) -- Error here
undefined
Produces
Couldn't match type ‘IO ()’ with ‘()’
Expected type: ReaderT UDCEnv IO () -> UDCEnv -> ()
Actual type: ReaderT UDCEnv IO () -> UDCEnv -> IO ()
In the first argument of ‘(<$>)’, namely ‘runReaderT’
In the first argument of ‘(<*>)’, namely
‘runReaderT
<$>
(uploadVersionFilesToCaches s3BucketName <$> maybeFilePath
<*> Just gitRepoNamesAndVersions)’
/Users/blender/Code/Personal/Haskell/Rome-Public/src/Lib.hs: 82, 73
Couldn't match type ‘Maybe’ with ‘ExceptT String IO’
Expected type: ExceptT String IO FilePath
Actual type: Maybe FilePath
In the second argument of ‘(<$>)’, namely ‘maybeFilePath’
In the first argument of ‘(<*>)’, namely
‘uploadVersionFilesToCaches s3BucketName <$> maybeFilePath’
I think the first error is because I'm missing some liftIO
somewhere.
However I have no idea what to do about the misunderstood Applicative.
I could case analysis on the Maybe of course instead of using Applicative but I would really prefer not to.
Edit: Oops, fixed a bug.
There seems to be a minor inconsistency in your question, because the do-block you provide contains a runReaderT ...
expression that doesn't match the expression given in your error message.
However, ultimately the problem is this: in a do-block of type ma
for some monad m
, each plain expression (and each right-hand side of an x <- y
expression) has to have type mb
for some b
. So, by using your runReaderT ...
expression in a do-block of type ExceptT String IO ()
, you're forcing Haskell to type-check it as ExceptT String IO a
for some a
. However, it's a Maybe (IO ())
, so that type-checking will fail.
You'd get a similar error if you tried:
foo :: ExceptT String IO ()
foo = do Just (putStrLn "won't work") -- has type Maybe (IO ())
undefined
You need to decide how to adapt the runReaderT ...
expression to the surrounding do-block. Two reasonable options are:
foo = do ...
maybe (throwError "reader was Nothing!") liftIO
$ runReaderT ...
undefined
which will throw an ExceptT
-style error if your maybeReader
is Nothing
or:
foo = do ...
maybe (return ()) liftIO
$ runReaderT ...
undefined
which will do .. erm .. nothing in case of Nothing
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.