子网站类型的奥秘



当从身份验证插件实现类型类时,我无法弄清楚我的Foundation.hs应该使用哪些类型/它使用了身份验证子站点:

我能感觉到我非常接近,但我缺乏理解。我只是尝试为登录/注册页面使用不同的布局。

在Foundation.hs中:


instance YesodAuthSimple App where
type AuthSimpleId App = UserId
...
-- Works
onRegisterSuccess :: YesodAuthSimple site => AuthHandler site Html
onRegisterSuccess = authLayout $ [whamlet|
$newline never
<div>
<h1>You Registered successfully.
<p>
Some text here.
|]  
-- Works when I do not write a type signature
loginTemplate toParent mErr = $(widgetFile "authpartials/login")

-- Does not work with or without type signatures
customAuthLayout widget = do 
master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
mcurrentRoute <- getCurrentRoute
pc <- widgetToPageContent $ do
$(widgetFile "custom-auth-layout")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")

432:15指的是widgetToPageContent呼叫。

在类型类定义 Simple.hs 中:

class (YesodAuth site, PathPiece (AuthSimpleId site)) => YesodAuthSimple site where
type AuthSimpleId site
...
customAuthLayout :: WidgetFor site () -> AuthHandler site Html
...

我从Foundation.hsdefaultLayout粘贴了customAuthLayout的定义

这是我从GHC得到的错误:

Foundation.hs:432:15: error:
• Could not deduce: m ~ HandlerFor App
from the context: MonadAuthHandler App m
bound by the type signature for:
customAuthLayout :: WidgetFor App () -> AuthHandler App Html
at src/Foundation.hs:(427,5)-(434,79)
‘m’ is a rigid type variable bound by
the type signature for:
customAuthLayout :: WidgetFor App () -> AuthHandler App Html
at src/Foundation.hs:(427,5)-(434,79)
Expected type: m (PageContent (Route App))
Actual type: HandlerFor App (PageContent (Route App))
• In a stmt of a 'do' block:
pc <- widgetToPageContent
$ do (do do (asWidgetT GHC.Base.. toWidget)
((blaze-markup-0.8.2.2:Text.Blaze.Internal.preEscapedText
GHC.Base.. Data.Text.pack)
"<!--  custom-auth-layout -->
<body class="d-flex align-items-center bg-auth border-top border-top-2 border-primary">")
....)
In the expression:
do master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
mcurrentRoute <- getCurrentRoute
....
In an equation for ‘customAuthLayout’:
customAuthLayout widget
= do master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
....
|
432 |         pc <- widgetToPageContent $ do
|               ^^^^^^^^^^^^^^^^^^^^^^^^...

我已经成功地将本教程用于普通(非子网站页面)https://ersocon.net/cookbooks/yesod/html-and-seo/custom-layouts

但是我被子网站类型绊倒了。我已经阅读了Michael Snoyman关于子网站类型的非常好的旧博客文章,但我无法理解GHC的错误消息。

我怀疑 Simple.hs 中的类型签名是错误的,或者我从函数定义中缺少一些东西。

尝试在widgetToPageContent之前添加liftHandler

...
pc <- liftHandler $ widgetToPageContent $ do
$(widgetFile "custom-auth-layout")
...

错误消息中的关键行是:

Could not deduce: m ~ HandlerFor App
...
Expected type: m (PageContent (Route App))
Actual type: HandlerFor App (PageContent (Route App))

它基本上告诉我们它期望一个更通用的类型m,但它得到了一个HandlerFor App。因此,解决方案只是使用liftHandler函数解除对widgetToPageContent的调用。

进一步详细说明,如果我们查看函数的类型签名widgetToPageContent,我们看到它返回HandlerFor site (PageContent (Route site))。在这种情况下,site实例化为App,这就是您在错误消息中看到HandlerFor App (PageContent (Route App))

同样,您的customLayout函数返回AuthHandler site HtmlAuthHandler只是一个类型同义词,它将site约束为等效于HandlerSite m的类型,也是YesodAuth的实例。这也解析为App,这就是为什么我们在错误消息中得到MonadAuthHandler App mm (PageContent (Route App))的原因。

最新更新