Why does this code work with Yesod.Persist's get404 but not getBy404?

天涯浪子 提交于 2020-02-25 05:53:27

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!