[英]How do I parse this GHC type check error message?
I have been stumped by this GHC (version 8.4.3) type check error. 我被这个GHC(版本8.4.3)类型检查错误所困扰。 This is an extract from a Haskell Servant code base I am working on.
这是我正在研究的Haskell Servant代码库的摘录。 If somebody can explain the reason for this message, I would be very grateful.
如果有人可以解释此消息的原因,我将不胜感激。 Apologies for the length of the code, but I was unable to reduce it any further.
对于代码的长度,我们深表歉意,但我无法进一步减少代码长度。
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
module Api2 where
import Control.Lens (preview)
import Control.Lens.Cons
import Control.Monad.Error.Class
import Control.Monad.Except (runExceptT)
import Control.Monad.IO.Class (liftIO, MonadIO)
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
import Crypto.JOSE.Compact
import Crypto.JOSE.Error
import Crypto.JWT (JWT, JWK, JWTError, verifyClaims, decodeCompact,
defaultJWTValidationSettings, stringOrUri, ClaimsSet,
AsJWTError)
import Data.Aeson (decode, encode)
import Data.Aeson.Types
import Data.Maybe (fromJust)
import Data.Text as T
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Data.Word8(isSpace)
import Network.Wai (Request, requestHeaders)
import Servant.API.Experimental.Auth (AuthProtect)
import Servant.Auth.Server (FromJWT, ToJWT)
import Servant.Server.Experimental.Auth (AuthHandler, AuthServerData,
mkAuthHandler)
import Servant.Server.Internal.ServantErr
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as L
data User = User
authHandler :: AuthHandler Request User
authHandler = mkAuthHandler authF2
authF2 :: (MonadIO m,
MonadError ServantErr m) =>
Request -> m User
authF2 req = do
case lookup "Authorization" (requestHeaders req) of
Nothing -> throwError err401
Just authH -> do
let (b, rest) = BS.break isSpace authH
if T.toLower (decodeUtf8 b) == "bearer"
then do
claims <- liftIO $ verifyJwt "" (L.fromStrict rest)
("audience"::String)
return $ User
else throwError err401
verifyJwt
:: forall e s. (Crypto.JWT.AsJWTError JWTError, (AsError e),
AsJWTError e,
Control.Lens.Cons.Cons s s Char Char, Monoid s) =>
FilePath
-> L.ByteString
-> s
-> IO (Either e Crypto.JWT.ClaimsSet)
verifyJwt jwkFilename jwtData aud = do
let
aud' = fromJust $ preview stringOrUri aud
conf = defaultJWTValidationSettings (== aud')
Just k <- decode <$> L.readFile jwkFilename
result <- runExceptT
(decodeCompact jwtData >>= verifyClaims conf (k :: JWK))
return result
When I load this file in GHC, I get the following error. 在GHC中加载此文件时,出现以下错误。
• Could not deduce (AsError e0) arising from a use of ‘verifyJwt’
from the context: (MonadIO m, MonadError ServantErr m)
bound by the type signature for:
authF2 :: forall (m :: * -> *).
(MonadIO m, MonadError ServantErr m) =>
Request -> m User
at servant-api-server/src/Api2.hs:(37,1)-(39,27)
The type variable ‘e0’ is ambiguous
These potential instances exist:
instance AsError Crypto.JOSE.Error.Error
-- Defined in ‘Crypto.JOSE.Error’
instance AsError JWTError -- Defined in ‘Crypto.JWT’
• In the second argument of ‘($)’, namely
‘verifyJwt "" (L.fromStrict rest) ("audience" :: String)’
In a stmt of a 'do' block:
claims <- liftIO
$ verifyJwt "" (L.fromStrict rest) ("audience" :: String)
In the expression:
do claims <- liftIO
$ verifyJwt "" (L.fromStrict rest) ("audience" :: String)
return $ User
|
48 | claims <- liftIO $ verifyJwt "" (L.fromStrict rest) ("audience"::String)
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When you call verifyJwt :: forall e s. ...
当您调用
verifyJwt :: forall e s. ...
verifyJwt :: forall e s. ...
, GHC figures out that you want to instantiate the s
type variable to String
but it has no way of figuring out what to instantiate the e
type variable to. verifyJwt :: forall e s. ...
,GHC指出您想将s
类型变量实例化为String
但无法确定将e
类型变量实例化为什么。
You can fix this by giving an explicit type signature to claims
, although you'll have to enable the ScopedTypeVariables
extension. 尽管必须启用
ScopedTypeVariables
扩展,但可以通过为claims
提供显式类型签名来解决此问题。 You can take your pick for which instance of AsError
you want. 您可以选择所需的
AsError
实例 。
For instance, picking e ~ Error
: 例如,选择
e ~ Error
:
authF2 :: (MonadIO m,
MonadError ServantErr m) =>
Request -> m User
authF2 req = do
case lookup "Authorization" (requestHeaders req) of
Nothing -> throwError err401
Just authH -> do
let (b, rest) = BS.break isSpace authH
if T.toLower (decodeUtf8 b) == "bearer"
then do
(claims :: Either Error Crypto.JWT.ClaimsSet) <- liftIO $ verifyJwt "" (L.fromStrict rest) ("audience"::String)
return $ User
else throwError err401
Unrelated to type errors, but don't you also want to check that claims
isn't a Left
before returning the User
? 与类型错误无关,但是您是否还不想在返回
User
之前检查claims
是否不是Left
?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.