简体   繁体   English

Monad变压器和可能的应用

[英]Monad Transformer and applicative Maybe

Inside a do block of a ExceptT String IO () ExceptT String IO ()的do块内

I have a function that produces a ReaderT like so: 我有一个生成ReaderT的函数,如下所示:

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: 我碰巧有一个Maybe FilePath所以我这样创建了ReaderT:

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

I can even run the ReaderT like so: 我什至可以像这样运行ReaderT:

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

Everything works fine as long as I use let expressions. 只要我使用let表达式,一切都可以正常工作。 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 我在上面的表达式中放下let以实际尝试对表达式求值后,Applicative将类型作为ExceptT String IO FilePath而不是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. 我认为第一个错误是因为我在某处缺少了一些liftIO

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. 当然,我可以对Maybe进行案例分析,而不是使用Applicative,但我真的不愿意。

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. 您的问题似乎存在一些细微的矛盾,因为您提供的do-block包含一个runReaderT ...表达式,该表达式与错误消息中给出的表达式不匹配。

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 . 但是,最终的问题是这样的:对于某些monad m ,在ma类型的do块中,每个简单表达式(以及x <- y表达式的每个右侧)必须对于某些b具有mb类型。 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 . 因此,通过使用您runReaderT ...表达类型的DO-块ExceptT String IO ()你这是在强迫Haskell的类型检查它作为ExceptT String IO a对一些a However, it's a Maybe (IO ()) , so that type-checking will fail. 但是,它是Maybe (IO ()) ,因此类型检查将失败。

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. 您需要确定如何使runReaderT ...表达式适应周围的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: 如果您的maybeReaderNothing ,则将抛出ExceptT风格的错误或:

foo = do ...
         maybe (return ()) liftIO
             $ runReaderT ...
         undefined

which will do .. erm .. nothing in case of Nothing . 万一Nothing

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM