我正在为Snap web framework写一个新的身份验证系统,因为内置模块不够模块化,并且它的某些功能对于我的应用程序来说是冗余/“自重” 。尽管这个问题与Snap完全无关。依赖类限制的模糊类型变量
虽然这样做,我遇到了模糊类型约束的问题。在下面的代码中,似乎很明显,back
的类型只能是函数类型中的类型变量b
,但GHC却抱怨该类型不明确。
如何更改以下代码,使back
的类型为b
,而不使用例如。 ScopedTypeVariables
(因为问题与约束有关,而不是具有过于普通的类型)?有什么地方需要功能依赖吗?
相关类型类:
data AuthSnaplet b u =
AuthSnaplet
{ _backend :: b
, _activeUser :: Maybe u
}
-- data-lens-template:Data.Lens.Template.makeLens
-- data-lens:Data.Lens.Common.Lens
-- generates: backend :: Lens (AuthSnaplet b u) b
makeLens ''AuthSnaplet
-- Some encrypted password
newtype Password =
Password
{ passwordData :: ByteString
}
-- data-default:Data.Default.Default
class Default u => AuthUser u where
userLogin :: Lens u Text
userPassword :: Lens u Password
class AuthUser u => AuthBackend b u where
save :: MonadIO m => b -> u -> m u
lookupByLogin :: MonadIO m => b -> Text -> m (Maybe u)
destroy :: MonadIO m => b -> u -> m()
-- snap:Snap.Snaplet.Snaplet
class AuthBackend b u => HasAuth s b u where
authSnaplet :: Lens s (Snaplet (AuthSnaplet b u))
失败代码:
-- snap:Snap.Snaplet.with :: Lens v (Snaplet v') -> m b v' a -> m b v a
-- data-lens-fd:Data.Lens.access :: MonadState a m => Lens a b -> m b
loginUser :: HasAuth s b u
=> Text -> Text -> Handler a s (Either AuthFailure u)
loginUser uname passwd = with authSnaplet $ do
back <- access backend
maybeUser <- lookupByLogin back uname -- !!! type of back is ambiguous !!!
-- ... For simplicity's sake, let's say the function ends like this:
return . Right . fromJust $ maybeUser
完整的错误:
src/Snap/Snaplet/Authentication.hs:105:31:
Ambiguous type variables `b0', `u0' in the constraint:
(HasAuth s b0 u0) arising from a use of `authSnaplet'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `with', namely `authSnaplet'
In the expression: with authSnaplet
In the expression:
with authSnaplet
$ do { back <- access backend;
maybeUser <- lookupByLogin back uname;
... }
src/Snap/Snaplet/Authentication.hs:107:16:
Ambiguous type variable `b0' in the constraint:
(AuthBackend b0 u) arising from a use of `lookupByLogin'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' expression:
maybeUser <- lookupByLogin back uname
In the second argument of `($)', namely
`do { back <- access backend;
maybeUser <- lookupByLogin back uname;
... }'
In the expression:
with authSnaplet
$ do { back <- access backend;
maybeUser <- lookupByLogin back uname;
... }
Haskell中的主要下划线通常表示“无关”值。据我所知这是纯粹的风格(编译器只是没有警告未使用的值),但我不会使用它们作为访问函数。 – 2011-12-17 16:57:04
AuthBackend是一个多参数类型的类。这可能是你需要功能依赖性,比如说“class [AuthBackend b u | u - > b]”。这意味着对于任何类型的“u”,只能有一个对应的类型“b”,它是这个类的一个实例。 – 2011-12-17 17:02:17
@Paul Johnson:主要的下划线是你如何使用'data-lens-template'派生镜片。他们从不直接使用。另外,我认为放弃警告只适用于像这样命名的参数。 – ehird 2011-12-17 17:12:29