我正在爲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