Тайна дочерних типов - PullRequest
2 голосов
/ 28 октября 2019

Я не могу понять, какие типы должны входить в мой Foundation.hs при реализации классов типов из плагина аутентификации / это использует дочерний сайт auth:

Я чувствую, что я очень близок, но яне хватает понимания. Я просто пытаюсь использовать другой макет для страниц входа / регистрации.

В 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

  ...

Я вставил определение customAuthLayout из defaultLayout из Foundation.hs

Вот ошибкаЯ получаю от 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

Но меня сбивают с толку типы дочерних сайтов. Я прочитал очень хороший старый пост Майкла Сноймана о типах дочерних сайтов, но не могу понять сообщение об ошибке GHC.

Я подозреваю, что либо подпись типа в Simple.hs неверна, либо я что-то упустил из определения функции.

1 Ответ

4 голосов
/ 29 октября 2019

Попробуйте добавить liftHandler до widgetToPageContent:

...
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. Таким образом, решение состоит в том, чтобы просто поднять вызов widgetToPageContent с помощью функции liftHandler.

Для дальнейшего рассмотрения, если мы посмотрим на сигнатуру типа функции widgetToPageContent, мы видим, что он возвращает HandlerFor site (PageContent (Route site)). В этом случае site создает экземпляр App, и это HandlerFor App (PageContent (Route App)), которое вы видите в сообщении об ошибке.

Аналогично, ваша функция customLayout возвращает AuthHandler site Html. AuthHandler - это просто синоним типа, ограничивающий site типом, эквивалентным HandlerSite m, который также является экземпляром YesodAuth. Это также приводит к App, и именно поэтому мы получаем MonadAuthHandler App m и m (PageContent (Route App)) в сообщении об ошибке.

...