开发者

I don't understand what this type family stuff in yesod is for

开发者 https://www.devze.com 2023-03-10 21:29 出处:网络
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.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消