Monad Transformer 和应用程序 Maybe

Monad Transformer and applicative Maybe

ExceptT String IO ()

的 do 块内

我有一个生成 ReaderT 的函数,如下所示:

type UDCEnv = (AWS.Env, Bool)

uploadVersionFilesToCaches :: S3.BucketName
                               -> FilePath
                               -> [GitRepoNameAndVersion]
                               -> ReaderT UDCEnv IO ()

我恰好有一个 Maybe FilePath 所以我像这样创建我的 ReaderT:

let maybeReader ::  Maybe (ReaderT UDCEnv IO ()) =
    uploadVersionFilesToCaches s3BucketName <$> maybeFilePath <*> Just gitRepoNamesAndVersions

我什至可以像这样 运行 ReaderT:

let maybeIO :: Maybe (IO ()) = 
    runReaderT <$> maybeReader <*> Just (env, shouldIgnoreLocalCache, verbose)

只要我使用 let 表达式一切正常。一旦我将 let 放在上面的表达式中以实际尝试对表达式求值,Applicative 就会将类型获取为 ExceptT String IO FilePath 而不是 Maybe

我省略的部分用...标记:

f :: ... -> ExceptT String IO ()
f ... = do
   ... 
   runReaderT <$> maybeReader <*> Just (env, shouldIgnoreLocalCache, verbose) -- Error here
   undefined

生产

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’

我认为第一个错误是因为我在某处遗漏了一些 liftIO

但是我不知道如何处理被误解的 Applicative。

我当然可以在 Maybe 上进行案例分析,而不是使用 Applicative,但我真的不想这样做。

编辑:糟糕,修复了一个错误。

您的问题似乎有一点不一致,因为您提供的 do-block 包含一个 runReaderT ... 表达式,与您在错误消息中给出的表达式不匹配。

然而,最终的问题是:在一个 m a 类型的 do-block 中,对于一些 monad m,每个普通表达式(以及 x <- y 表达式) 对于某些 b 必须具有类型 m b。因此,通过在 ExceptT String IO () 类型的 do 块中使用您的 runReaderT ... 表达式,您强制 Haskell 将其类型检查为 ExceptT String IO a 对于某些 a.但是,它是 Maybe (IO ()),因此类型检查将失败。

如果您尝试过,您会得到类似的错误:

foo :: ExceptT String IO ()
foo = do Just (putStrLn "won't work")   -- has type Maybe (IO ())
         undefined

您需要决定如何使 runReaderT ... 表达式适应周围的 do 块。两个合理的选择是:

foo = do ...
         maybe (throwError "reader was Nothing!") liftIO
             $ runReaderT ...
         undefined

如果您的 maybeReaderNothing 或:

,这将引发 ExceptT 式的错误
foo = do ...
         maybe (return ()) liftIO
             $ runReaderT ...
         undefined

Nothing 的情况下,这将执行 .. 呃 .. 什么也做不了。