【问题标题】:Haskell Type Error while using HTTP-Conduit使用 HTTP-Conduit 时出现 Haskell 类型错误
【发布时间】:2017-11-29 20:16:26
【问题描述】:

我正在为 Yesod 应用程序进行 OAuth2 身份验证,但我遇到了一个我真的不明白的类型错误。代码现在坏了,我扔了几个:: IO ()undefineds来帮助我隔离类型错误,但相关代码是:

getAccessToken :: Manager -> OAuth2 -> ExchangeToken -> IO (OAuth2Result Errors OAuth2Token)
getAccessToken manager oa code = do

  let (uri, defaultBody) = accessTokenUrl oa code
  let body = defaultBody <> [ ("client_id", TE.encodeUtf8 . oauthClientId $ oa )
                            , ("client_secret", TE.encodeUtf8 . oauthClientSecret $ oa)
                            , ("resource", TE.encodeUtf8 . oauthClientId $ oa)
                            ]

  response <- performOAuth2PostRequest manager oa uri body

  return undefined

performOAuth2PostRequest :: Manager -> OAuth2 -> URI -> PostBody -> IO (Response ByteString)
performOAuth2PostRequest manager oa uri body  = do
  defaultReq <- uriToRequest uri

  let addBasicAuth = applyBasicAuth (TE.encodeUtf8 . oauthClientId $ oa)
                                    (TE.encodeUtf8 . oauthClientSecret $ oa)

  let req = (addBasicAuth . updateRequestHeaders Nothing) defaultReq

  (httpLbs (urlEncodedBody body req) manager) :: IO (Response ByteString)

请注意,我使用ScopedTypeVariables 扩展名专门将httpLbs (urlEnc...) manager 操作的类型设置为IO (Response ByteString)。此外,这行代码应该是一个 IO 操作,因为它是在 IO 操作的顶层执行的。

事实上,我运行了一个 GHCi 会话并做到了:

Network.OAuth.OAuth2.HttpClient Network.OAuth.OAuth2.Internal 
Network.HTTP.Conduit Data.Functor Prelude> :t httpLbs
httpLbs
  :: Control.Monad.IO.Class.MonadIO m =>
     Request
     -> Manager -> m (Response Data.ByteString.Lazy.Internal.ByteString)

这证实了我的理解,即 httpLbs 应该产生 MonadIO m =&gt; m (Response ByteString)

但这是我得到的错误:

• Couldn't match type ‘Response
                         Data.ByteString.Lazy.Internal.ByteString’
                 with ‘IO (Response ByteString)’
  Expected type: Manager -> IO (Response ByteString)
    Actual type: Manager
                 -> Response Data.ByteString.Lazy.Internal.ByteString
• The function ‘httpLbs’ is applied to two arguments,
  its type is ‘Request
               -> m1 (Response Data.ByteString.Lazy.Internal.ByteString)’,
  it is specialized to ‘Request
                        -> Manager -> Response Data.ByteString.Lazy.Internal.ByteString’

为什么 GHC 将 m 专门用于 Response 而不是 IO?我该如何解决?

【问题讨论】:

  • 据我所知,实际问题是预期的类型是严格的ByteString,而实际的类型是懒惰的ByteString(编译器通过打印帮助指示它是不同的类型它完全合格)。但是,该错误似乎是虚假的,因为没有办法将httpLbs 的类型专门化为Request -&gt; Manager -&gt; Response Lazy.ByteString - 即使您确实设置了m ~ Response(这将给出另一个非常明显的错误-no instance for MonadIO Response)然后实际实例化将是... -&gt; Response (Response Lazy.ByteString)
  • 旁白:您在最后一行中给出的类型注释没有使用ScopedTypeVariables,因为IO (Response ByteString) 不包含任何类型变量;而且这也是完全多余的,因为函数上的类型签名已经给出了类型。

标签: haskell http-conduit


【解决方案1】:

您没有包含导入语句,因此很难调试。不过我最好的猜测是您已经导入了Network.HTTP.Simple,它提供了不需要显式Manager 参数的函数。我从提供预期类型的​​错误消息中猜到了这一点:

Request -> m1 (Response Data.ByteString.Lazy.Internal.ByteString)

解决方案:要么更改导入,要么删除 Manager 参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 2011-10-17
    • 2017-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多