I don't understand what this type family stuff in yesod is for
I went through yesod book and the source and learned pretty much how everything works. But before I write my own stuff, there is one thing in the scaffolded site that I just don't understand.
So I scaffold a site "copywww" and in the file CopyWWWState.hs there is the code:
instance YesodPersist CopyWWWState where
type YesodDB CopyWWWState = SqlPersist
runDB db = liftIOHandler
$ fmap connPool getYesod >>= Settings.runConnectionPool db
instance YesodAuth CopyWWWState where
type AuthId CopyWWWState = UserId
-- Where to send a user after successful login
loginDest _ = RootR
-- Where to send a user after logout
logoutDest _ = RootR
getAuthId creds = runDB $ do
x <- getBy $ UniqueUser $ credsIdent creds
case x of
Just (uid, _) -> return $ Just uid
Nothing -> do
fmap Just $ insert $ User (credsIdent creds) Nothing
authPlugins = [ authOpenId
, authEmail
]
The line开发者_如何学编程s that I don't understand are the ones:
type AuthId CopyWWWState = UserId
type YesodDB CopyWWWState = SqlPersist
When I remove them, I get errors obviously, but I'm not sure why they are required in the first place. When I search the source for "UserId" or "SqlPersist" I come up with nothing that seems promising. What exactly does this code need to be there for? What benefit does yesod get from using type families in these classes?
There's quite a bit going on in the scaffold that might not be immediately obvious. In the config/model, there is a persistent entity defined something like:
User
name String
foo String
This will create a type User which is an instance of PersistEntity and a type UserId which is used as such:
instance PersistEntity User where
...
Key User = UserId
The reason that the scaffold puts in:
type AuthId CopyWWWState = UserId
is just that user is a logical reference point. Now, in your code, anytime you call requireAuth
you'll get something like Handler User
and requireAuthId
will give you a Handler UserId
which is equivalent to Handler (Key User)
. You're free to change these to anything you'd like, but you'll have to change some of the other functions in the YesodAuth typeclass instance.
Hope this helps. Yesod rocks. takes a week or two to get the feel of how it sticks together but when you do things like this are quite powerful.
Type families are similar to functional dependecies. They both provide a way to abstract a typeclass over more than one parameter while keeping the typechecker happy. The local type
just means, that you have an extra parameter that is bound by the instance. This means, that the instance can decide by itself which type to use at that place. An instance may also use a more general type instead of a specific to give the user the choice. In your case, you possibly rely on the fact, that ypur database type YesodDB
is in fact a SQL database (SqlPersist
). So this information is needed to satisfy the typechecker.
精彩评论