Can't use runFormPost in Yesod Email Authentication's apLogin

112 Views Asked by At

I'm trying to write an apLogin for Yesod's Email Authentication plugin and form helpers are throwing a type error. The loginForm can't be read by runFormPost. I've tried several different combinations of type signatures, but this error message seems the clearest. It seems like I have the wrong top-level constraint, or that I'm missing one. What is the best way to set this up so that the proper types can be inferred?

authEmail :: (YesodAuthEmail m) => AuthPlugin m
authEmail =
    AuthPlugin "email" dispatch login
  where
    login toParent =
        toWidget $ do
            ((_,widget),enctype) <-  runFormPost loginForm
            [whamlet|
                <form method="post" action="@{toParent loginR}">
            |]
    loginForm extra = do
        let emailSettings = FieldSettings {
            fsLabel = SomeMessage Msg.Email,
            fsTooltip = Nothing,
            fsId = Just "email",
            fsName = Just "email",
            fsAttrs = [("autofocus", "")]
        }

        (emailRes, emailView) <- mreq emailField emailSettings Nothing

        let userRes = UserForm <$> emailRes
        let widget = do
            [whamlet|
                #{extra}
                ^{fvInput emailView}
            |]

        return (userRes, widget)

This is the error:

Could not deduce (MonadIO m0) arising from a use of ‘loginForm’
from the context (YesodAuthEmail m)
  bound by the type signature for
             authEmail :: YesodAuthEmail m => AuthPlugin m
  at Yesod/Auth/Email.hs:260:14-47
or from (MonadWidget m1, YesodAuth (HandlerSite m1))
  bound by the inferred type of
           login :: (MonadWidget m1, YesodAuth (HandlerSite m1)) =>
                    (AuthRoute -> Route (HandlerSite m1)) -> m1 ()
  at Yesod/Auth/Email.hs:(270,5)-(275,14)
The type variable ‘m0’ is ambiguous
Note: there are several potential instances:
  instance MonadIO m =>
           MonadIO
             (conduit-1.2.6.1:Data.Conduit.Internal.Conduit.ConduitM i o m)
    -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Conduit’
  instance MonadIO m =>
           MonadIO (conduit-1.2.6.1:Data.Conduit.Internal.Pipe.Pipe l i o u m)
    -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Pipe’
  instance MonadIO IO -- Defined in ‘Control.Monad.IO.Class’
  ...plus 18 others
In the first argument of ‘runFormPost’, namely ‘loginForm’
In a stmt of a 'do' block:
  ((_, widget), enctype) <- runFormPost loginForm
In the second argument of ‘($)’, namely
  ‘do { ((_, widget), enctype) <- runFormPost loginForm;
        (do { (asWidgetT . toWidget)
                ((Text.Blaze.Internal.preEscapedText . T.pack)
                   "<form method=\"post\" action=\"");
              (getUrlRenderParams
               >>=
                 (\ urender_ajDM
                    -> (asWidgetT . toWidget)
                         (toHtml (\ u_ajDN -> urender_ajDM u_ajDN ... (toParent loginR)))));
              (asWidgetT . toWidget)
                ((Text.Blaze.Internal.preEscapedText . T.pack)
                   "\"></form>\n") }) }’

Code with handlerToWidget correction:

authEmail :: (YesodAuthEmail m) => AuthPlugin m
authEmail =
    AuthPlugin "email" dispatch login
where
    login toParent = do
            ((_,widget),enctype) <- handlerToWidget $ runFormPost loginForm
            [whamlet|
                <form method="post" action="@{toParent loginR}">
            |]
    loginForm extra = do
        let emailSettings = FieldSettings {
            fsLabel = SomeMessage Msg.Email,
            fsTooltip = Nothing,
            fsId = Just "email",
            fsName = Just "email",
            fsAttrs = [("autofocus", "")]
        }

        (emailRes, emailView) <- mreq emailField emailSettings Nothing

        let userRes = UserForm <$> emailRes
        let widget = do
            [whamlet|
                #{extra}
                ^{fvInput emailView}
            |]

        return (userRes, widget)

Error:

    Could not deduce (MonadIO m0) arising from a use of ‘loginForm’
    from the context (YesodAuthEmail m)
      bound by the type signature for
                 authEmail :: YesodAuthEmail m => AuthPlugin m
      at Yesod/Auth/Email.hs:260:14-47
    or from (MonadIO m1,
             MonadBaseControl IO m1,
             exceptions-0.8.2.1:Control.Monad.Catch.MonadThrow m1,
             YesodAuth site)
      bound by the inferred type of
               login :: (MonadIO m1, MonadBaseControl IO m1,
                         exceptions-0.8.2.1:Control.Monad.Catch.MonadThrow m1,
                         YesodAuth site) =>
                        (AuthRoute -> Route site) -> WidgetT site m1 ()
      at Yesod/Auth/Email.hs:(270,5)-(275,14)
    The type variable ‘m0’ is ambiguous
    Note: there are several potential instances:
      instance MonadIO m =>
               MonadIO
                 (conduit-1.2.6.1:Data.Conduit.Internal.Conduit.ConduitM i o m)
        -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Conduit’
      instance MonadIO m =>
               MonadIO (conduit-1.2.6.1:Data.Conduit.Internal.Pipe.Pipe l i o u m)
        -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Pipe’
      instance MonadIO IO -- Defined in ‘Control.Monad.IO.Class’
      ...plus 18 others
    In the first argument of ‘runFormPost’, namely ‘loginForm’
    In the second argument of ‘($)’, namely ‘runFormPost loginForm’
    In a stmt of a 'do' block:
      ((_, widget), enctype) <- handlerToWidget $ runFormPost loginForm

Without toWidgetHandler error:

    Could not deduce (MonadIO m0) arising from a use of ‘loginForm’
    from the context (YesodAuthEmail m)
      bound by the type signature for
                 authEmail :: YesodAuthEmail m => AuthPlugin m
      at Yesod/Auth/Email.hs:260:14-47
    or from (MonadIO m1,
             MonadBaseControl IO m1,
             exceptions-0.8.2.1:Control.Monad.Catch.MonadThrow m1,
             YesodAuth site)
      bound by the inferred type of
               login :: (MonadIO m1, MonadBaseControl IO m1,
                         exceptions-0.8.2.1:Control.Monad.Catch.MonadThrow m1,
                         YesodAuth site) =>
                        (AuthRoute -> Route site) -> WidgetT site m1 ()
      at Yesod/Auth/Email.hs:(271,5)-(275,10)
    The type variable ‘m0’ is ambiguous
    Note: there are several potential instances:
      instance MonadIO m =>
               MonadIO
                 (conduit-1.2.6.1:Data.Conduit.Internal.Conduit.ConduitM i o m)
        -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Conduit’
      instance MonadIO m =>
               MonadIO (conduit-1.2.6.1:Data.Conduit.Internal.Pipe.Pipe l i o u m)
        -- Defined in ‘conduit-1.2.6.1:Data.Conduit.Internal.Pipe’
      instance MonadIO IO -- Defined in ‘Control.Monad.IO.Class’
      ...plus 18 others
    In the first argument of ‘runFormPost’, namely ‘loginForm’
    In a stmt of a 'do' block:
      ((_, widget), enctype) <- runFormPost loginForm
    In the expression:
      do { ((_, widget), enctype) <- runFormPost loginForm;
           (do { (asWidgetT . toWidget)
                   ((Text.Blaze.Internal.preEscapedText . T.pack)
                      "<form method=\"post\" action=\"");
                 (getUrlRenderParams
                  >>=
                    (\ urender_ajDM
                       -> (asWidgetT . toWidget)
                            (toHtml (\ u_ajDN -> urender_ajDM u_ajDN ... (toParent loginR)))));
                 (asWidgetT . toWidget)
                   ((Text.Blaze.Internal.preEscapedText . T.pack) "\"></form>\n") }) }
1

There are 1 best solutions below

4
On

I'm not certain, but I think your toWidget call is your primary problem. Also, you'll need to lift your runFormPost from Handler to Widget, which can be done with handlerToWidget.