问题
Let's say I have a table of dog names and breeds as follows:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Dog
name Text
breed Text
UniqueDog name
|]
I have the following routes:
mkYesod "DogApp" [parseRoutes|
/ RootR GET
/dog/name/#Text DogNameR GET
/dog/id/#DogId DogIdR GET
|]
And I'm trying to create a page that returns the breed of the dog given it's name. I can do this with the Id in the URL via the getDogIdR route just fine:
getDogIdR :: DogId -> Handler RepHtml
getDogIdR dogId = do
dog <- runDB $ get404 dogId
defaultLayout $ do
[whamlet|
<p>
<b>#{dogName dog}
<p>
#{dogBreed dog}
|]
However, if I try creating the same page with the getDogNameR route,
getDogNameR :: Text -> Handler RepHtml
getDogNameR maybeDogName = do
dog <- runDB $ getBy404 (UniqueDog maybeDogName)
defaultLayout $ do
[whamlet|
<p>
<b>#{dogName dog}
<p>
#{dogBreed dog}
|]
I get the following error:
dog.hs:73:20:
Couldn't match type `Entity' with `DogGeneric'
In the return type of a call of `getBy404'
In the second argument of `($)', namely
`getBy404 (UniqueDog maybeDogName)'
In a stmt of a 'do' block:
dog <- runDB $ getBy404 (UniqueDog maybeDogName)
dog.hs:73:20:
Kind incompatibility when matching types:
backend0 :: (* -> *) -> * -> *
DogGeneric SqlPersist :: *
In the return type of a call of `getBy404'
In the second argument of `($)', namely
`getBy404 (UniqueDog maybeDogName)'
In a stmt of a 'do' block:
dog <- runDB $ getBy404 (UniqueDog maybeDogName)
Why does this fail, and how can I fix it?
It appears that the get404 and getBy404 functions return different types. If I change the getDogNameR route as follows, it runs just fine:
getDogNameR :: Text -> Handler RepHtml
getDogNameR maybeDogName = do
dog <- runDB $ getBy404 (UniqueDog maybeDogName)
defaultLayout $ do
[whamlet|
<p>
<b>Dog found!
|]
回答1:
It appears that the get404 and getBy404 functions return different types.
Right.
get404 :: (PersistStore (t m), PersistEntity val, Monad (t m), m ~ GHandler sub master,
MonadTrans t, PersistMonadBackend (t m) ~ PersistEntityBackend val)
=> Key val -> t m val
getBy404 :: (PersistUnique (t m), PersistEntity val, m ~ GHandler sub master,
Monad (t m), MonadTrans t, PersistEntityBackend val ~ PersistMonadBackend (t m))
=> Unique val -> t m (Entity val)
So getBy404
returns your dog wrapped in an Entity where you have the pure dog from get404
, and your second codeshould work if you replace
<b>#{dogName dog}
with
<b>#{dogName (entityVal dog)}
and similarly for the dogBreed
, or, more conveniently, if you deconstruct the returned Entity
on binding
Entity{entityVal = dog} <- runDB $ getBy404 ...
来源:https://stackoverflow.com/questions/13793336/why-does-this-code-work-with-yesod-persists-get404-but-not-getby404