【问题标题】:Monad Transformer and applicative MaybeMonad Transformer 和应用 Maybe
【发布时间】:2017-04-14 09:13:01
【问题描述】:

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,但我真的不想这样做。

【问题讨论】:

  • 从错误来看,你缺少的是return,而不是liftIO
  • @arrowd 很可能,但不幸的是,这对我的应用问题没有帮助。也许这不是开始的正确方法?
  • 您能否包含runReaderT ... 表达式实际出现的代码?最有可能的是,它在 do-block 中的使用方式是 Haskell 试图将其键入为 ExceptT String IO () 而不是 Maybe (IO ())。这最终将解释这两个错误,因为Maybe 不是ExceptT String IO,而() 不是IO ()。它可能就像添加一个标准的 Maybe-to-ExceptT 接口一样简单。
  • @K.A.Buhr 它只是出现在 do 块的中间 ExceptT String IO () 查看编辑

标签: haskell monads monad-transformers applicative maybe


【解决方案1】:

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

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

然而,最终的问题是:在一个 m a 类型的 do-block 中,对于某些 monad m,每个普通表达式(以及 x &lt;- y 表达式的每个右侧)都必须具有类型 @ 987654325@ 一些b。因此,通过在 ExceptT String IO () 类型的 do-block 中使用 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-block。两个合理的选择是:

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

如果您的maybeReaderNothing 或:

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

Nothing 的情况下什么都不会。

【讨论】:

  • 你说得对,我完全被错误消息和所有那些 Ts 弄糊涂了。一般来说,我发现编写 monad 转换器非常困难,maybe (wink wink) 我做错了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
相关资源
最近更新 更多