Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

haskell

yesod

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 lines 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?

like image 307
David McHealy Avatar asked Jun 07 '11 17:06

David McHealy


2 Answers

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.

like image 160
max Avatar answered Oct 18 '22 21:10

max


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.

like image 2
fuz Avatar answered Oct 18 '22 21:10

fuz