Pregunta

I'm working on a Yesod subsite. Basically, it is a blog. I am having problems attaching forms to the handlers. Consider:

getSubBlogR :: Yesod master
            => YesodPersist master
            => PersistQuery (YesodPersistBackend master (HandlerT master IO))
            => RenderMessage master FormMessage
            => HandlerT Blog (HandlerT master IO) Html
getSubBlogR = lift $ do
  articles              <- runDB $ selectList [] [Asc ArticleDate]
  day                   <- liftIO $ (utctDay <$> getCurrentTime)
  (formWidget, enctype) <- generateFormPost $ (articleForm day)

  defaultLayout $ [whamlet|
    <div .articles>
      $forall Entity _ article <- articles    
        ^{articleWidget article}     
  |]

As it stands, this does compile. But I'm not actually using the formWidget, and I would really like to. I'd like something "like"

getSubBlogR :: Yesod master
            => YesodPersist master
            => PersistQuery (YesodPersistBackend master (HandlerT master IO))
            => RenderMessage master FormMessage
            => HandlerT Blog (HandlerT master IO) Html
getSubBlogR = lift $ do
  articles              <- runDB $ selectList [] [Asc ArticleDate]
  day                   <- liftIO $ (utctDay <$> getCurrentTime)
  (formWidget, enctype) <- generateFormPost $ (articleForm day)

  defaultLayout $ [whamlet|
    <div .articles>
      $forall Entity _ article <- articles    
        ^{articleWidget article}
      <div .panel .panel-default>
        <div .panel-heading><h1>Add Article
        <div .panel-body>
          <form method="post" action=@{SubBlogR} enctype=#{enctype}>
            ^{formWidget}
  |]

But this does not compile. I get the error:

src/Yesod/Blog/Handler.hs:64:28:
    Could not deduce (master ~ Blog)
    from the context (Yesod master,
                      YesodPersist master,
                      PersistQuery (YesodPersistBackend master (HandlerT master IO)),
                      RenderMessage master FormMessage)
      bound by the type signature for
                 getSubBlogR
...
  Expected type: WidgetT
                 master IO (Route Blog -> [(Text, Text)] -> Text)
  Actual type: WidgetT
                 master
                 IO
                 (Route (HandlerSite (WidgetT master IO)) -> [(Text, Text)] -> Text)

Okay, fair enough. I understand that 'master' and 'Blog' are not the same types. But how do I get "the diagram" to commute?

¿Fue útil?

Solución

Be sure to add type annotations to all your forms! This is why Michael Snoyman asked for the type of articleForm. My subsite refused to typecheck with similar errors because I didn't annotate this function:

simpleSourceForm = DataSourceInput
  <$> areq textField "Name" Nothing
  <*> areq intField "Start" Nothing
  <*> areq intField "End" Nothing

That gave me errors such as these:

Yesod\DataSource.hs:58:36:
Couldn't match type `m0' with `HandlerT m IO'
  because type variable `m' would escape its scope
This (rigid, skolem) type variable is bound by
  the type signature for
    postDataSourceInputR :: YesodDataSource m =>
                            HandlerT DataSource (HandlerT m IO) Html

Yesod\DataSource.hs:49:7:
No instance for (RenderMessage (HandlerSite m0) FormMessage)
  arising from a use of `areq'
In the second argument of `(<$>)', namely
  `areq textField "Name" Nothing'
In the first argument of `(<*>)', namely
  `DataSourceInput <$> areq textField "Name" Nothing'
In the first argument of `(<*>)', namely
  `DataSourceInput <$> areq textField "Name" Nothing
   <*> areq intField "Start" Nothing'

Yesod\DataSource.hs:30:22:
Could not deduce (m ~ HandlerSite m0)
from the context (YesodDataSource m)
  bound by the type signature for
             getDataSourceInputR :: YesodDataSource m =>
                                    HandlerT DataSource (HandlerT m IO) Html

Annotating the function fixed everything:

simpleSourceForm :: YesodDataSource m => AForm (HandlerT m IO) DataSourceInput
simpleSourceForm = DataSourceInput
  <$> areq textField "Name" Nothing
  <*> areq intField "Start" Nothing
  <*> areq intField "End" Nothing

(I'll also include the YesodDataSource typeclass for informational purposes)

class (RenderMessage master FormMessage, Yesod master) => YesodDataSource master
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top