Search code examples
haskelltypesyesod

Couldn't match expected type in yesod blog example


I am trying to get the blog example to run, but there is a problem with types in some handler functions and I don't know how to fix it.

The example I am trying to run is posted here: Yesod blog example I changed a little bit of it, I added types to defaultLayout function and made it an instance of Yesod to get rid of double definitions.

defLayout :: GWidget a Blog () -> GHandler a Blog RepHtml
defLayout inside = do
  mmsg <- getMessage
  pc <- widgetToPageContent $ do
      toWidget [lucius|
body {
width: 760px;
margin: 1em auto;
font-family: sans-serif;
}
textarea {
width: 400px;
height: 200px;
}
#message {
color: #900;
}
|]
      inside 
  hamletToRepHtml [hamlet|
$doctype 5
<html>
    <head>
        <title>#{pageTitle pc}
        ^{pageHead pc}
    <body>
        $maybe msg <- mmsg
            <div #message>#{msg}
        ^{pageBody pc}
|]

instance Yesod Blog where
    approot = ApprootStatic "http://localhost:3000"
    defaultLayout = defLayout

These are the functions that give me problems:

getBlogR :: Handler RepHtml
getBlogR = do
  muser <- maybeAuth
  entries <- runDB $ selectList [] [Desc EntryPosted]
  ((_, entryWidget), enctype) <- generateFormPost entryForm
  defaultLayout $ do
             setTitleI MsgBlogArchiveTitle
             [whamlet|
$if null entries
    <p>_{MsgNoEntries}
$else
    <ul>
        $forall Entity entryId entry <- entries
            <li>
                <a href=@{EntryR entryId}>#{entryTitle entry}
$maybe Entity _ user <- muser
    $if isAdmin user
        <form method=post enctype=#{enctype}>
              ^{entryWidget}
              <div>
                  <input type=submit value=_{MsgNewEntry}>
$nothing
    <p>
         <a href=@{AuthR LoginR}>_{MsgLoginToPost}
|]

getEntryR :: EntryId -> Handler RepHtml
getEntryR entryId = do
  (entry, comments) <- runDB $ do
          entry <- get404 entryId
          comments <- selectList [] [Asc CommentPosted]
          return (entry, map entityVal comments)
  muser <- maybeAuth
  ((_, commentWidget), enctype) <- generateFormPost (commentForm entryId)
  defaultLayout $ do
    setTitleI $ MsgEntryTitle $ entryTitle entry
    [whamlet|
<h1>#{entryTitle entry}
<article>#{entryContent entry}
    <section .comments>
        <h1>_{MsgCommentsHeading}
        $if null comments
            <p>_{MsgNoComments}
        $else
             $forall Comment _entry posted _user name text <- comments
                 <div .comment>
                      <span .by>#{name}
                      <span .at>#{show posted}
                      <div .content>#{text}
        <section>
            <h1>_{MsgAddCommentHeading}
            $maybe _ <- muser
                <form method=post enctype=#{enctype}>
                    ^{commentWidget}
                    <div>
                        <input type=submit value=_{MsgAddCommentButton}>
            $nothing
                <p>
                    <a href=@{AuthR LoginR}>_{MsgLoginToComment}
|]

Here is the output I get when I try to run it:

blog.hs:147:4:
    Couldn't match expected type `GWidget Blog Blog ()'
                with actual type `(t0, t1)'
    In the pattern: (_, entryWidget)
    In the pattern: ((_, entryWidget), enctype)
    In a stmt of a 'do' block:
      ((_, entryWidget), enctype) <- generateFormPost entryForm

blog.hs:202:4:
    Couldn't match expected type `GWidget Blog Blog ()'
                with actual type `(t0, t1)'
    In the pattern: (_, commentWidget)
    In the pattern: ((_, commentWidget), enctype)
    In a stmt of a 'do' block:
      ((_, commentWidget), enctype) <- generateFormPost
                                         (commentForm entryId)

Solution

  • The type of generateFormPost has changed since the blog article, it used to be

    generateFormPost :: RenderMessage master FormMessage =>
                        (Html -> MForm sub master (FormResult a, xml)) ->
                        GHandler sub master ((FormResult a, xml), Enctype)
    

    in yesod-form-0.4.* but now it is

    generateFormPost :: RenderMessage master FormMessage => 
                        (Markup -> MForm sub master (FormResult a, xml)) -> 
                        GHandler sub master (xml, Enctype)
    

    The type error should [I think, never used yesod] go away if you use yesod-form < 1, or if you replace

    ((_, entryWidget), enctype) <- generateFormPost entryForm
    

    with

    (entryWidget, enctype) <- generateFormPost entryForm
    

    to reflect the change in the type of generateFormPost.