首页 > 解决方案 > 无法在 Network.URI 上匹配类型可能与非可能

问题描述

假设我想解析一个环境变量,并在没有它的情况下默认为 localhost,使用https://hackage.haskell.org/package/network-2.3/docs/Network-URI.html

我可以这样写一个函数:

parseRabbitURI :: Text -> Maybe URI.URI
parseRabbitURI "" = URI.parseURI "amqp://guest:guest@127.0.0.1/"
parseRabbitURI uri = (URI.parseURI . toS) uri

这工作正常。现在假设我要处理错误。我注意到 parseURIMaybe表面上返回 a 我只需要对其进行模式匹配。所以我创建了一个自定义错误:

data CustomError = MyCustomError Text deriving(Show)

我创建了一个辅助函数:

parsedExtractor
  :: MonadError CustomError.MyCustomError m
  => Text
  -> Maybe URI.URI
  -> m(URI.URI)
parsedExtractor originalString Nothing = throwError $ FlockErrors.FailedToParseURI originalString
parsedExtractor _ (Just uri) = do
  pure uri

最后,我修改了我的初始函数:

parseRabbitURI :: MonadError CustomError.MyCustomError m => Text -> m(URI.URI)
parseRabbitURI "" = URI.parseURI "amqp://guest:guest@127.0.0.1/" >>= parsedExtractor "amqp://guest:guest@127.0.0.1/"
parseRabbitURI uri = (URI.parseURI . toS) uri >>= parsedExtractor uri

这无法编译:

• Couldn't match type ‘URI.URI’ with ‘Maybe URI.URI’
  Expected type: URI.URI -> Maybe URI.URI
    Actual type: Maybe URI.URI -> Maybe URI.URI
• In the second argument of ‘(>>=)’, namely ‘parsedExtractor uri’
  In the expression: (URI.parseURI . toS) uri >>= parsedExtractor uri
  In an equation for ‘parseRabbitURI’:
      parseRabbitURI uri
        = (URI.parseURI . toS) uri >>= parsedExtractor uri

| 23 | parseRabbitURI uri = (URI.parseURI . toS) uri >>= parsedExtractor uri |

对于我的一生,我无法弄清楚为什么。如果初始实现返回一个 Maybe,为什么它会转换为我无法通过的解包器 URI.URI?

至关重要的是,当我将模式更改parsedExtractor为期望字符串时,它无法使用反向消息进行编译(

Couldn't match expected type ‘URI.URI’
                      with actual type ‘Maybe URI.URI’

我觉得我一定错过了一些完全基本的东西。这里发生了什么?

标签: haskelltypeserror-handlingtype-systemsmaybe

解决方案


对于我的一生,我无法弄清楚为什么。如果初始实现返回一个 Maybe,为什么它会转换为我无法通过的解包器 URI.URI?

要引用>>=来自Control.Monad的定义,它具有类型签名:

(>>=) :: m a -> (a -> m b) -> m b

现在,比较表达式:

(URI.parseURI . toS) uri >>= parsedExtractor uri

我们有:

m a        ~ (URI.parseURI . toS) uri
(a -> m b) ~ parsedExtractor uri

由于(URI.parseURI . toS) uri返回类型Maybe URI.URIMaybe是 的一个实例Monad,所以

m a ~ Maybe URI.URI 

(a -> m b) ~ (URI.URI -> m b) 

并且m b可以推断为m (URI.URI),因此预期之后的函数(即parsedExtractor uri>>=的类型为:

(URI.URI -> m (URI.URI))

但实际并非如此。


推荐阅读