5

BlazeHtml 教程建议使用 Reader monad使用BlazeHtml进行真实世界的模板化,但没有说明应该如何完成。我尝试遵循此建议。结果让我很困惑。

为了说明,假设我有一个简单的 User 类型,并且我想使用单独的函数来编写我的 HTML,一个用于布局,另一个用于显示用户信息的 HTML 页面的一部分。如果我使用 Reader Monad,它看起来像这样:

data User = User {
    username :: Text
  , userId :: nt
  } deriving (Show)

userBox :: Reader User Html
userBox = do
  user <- ask
  return $ do
      dl $ do
        dt $ "Username"
        dd $ H.toHtml $ username user
        dt $ "UserId"
        dd $ H.toHtml $ userId user

page :: Reader User Html
page = do
  user <- ask
  return $ H.docTypeHtml $ do
    H.head $ title "Reader Monad Blaze Example"
    H.body $ do
      h1 $ "Hello world"
      runReader userBox user

将此与我不使用 Reader monad 的版本进行比较:

userBox :: User -> Html
userBox user = do
      dl $ do
        dt $ "Username"
        dd $ H.toHtml $ username user
        dt $ "UserId"
        dd $ H.toHtml $ userId user

page :: User -> Html
page user = do
  H.docTypeHtml $ do
    H.head $ title "Blaze Example, No Reader Monad"
    H.body $ do
      h1 $ "Hello world"
      userBox user

所以我很难看到 Reader Monad 如何在实际用例中真正收紧模板代码。我错过了什么吗?

4

2 回答 2

7

如果你扩展你的类型,你会看到

page :: Reader User Html
     :: Reader User Markup
     :: Reader User (MarkupM ())

因此,您可能会通过使用变压器堆栈获得更多杠杆作用。

l :: (Html -> Html) -> ReaderT r MarkupM () -> ReaderT r MarkupM ()
l = mapReaderT

r :: Html -> ReaderT r MarkupM ()
r = lift

asksHtml :: ToMarkup a => (r -> a) -> ReaderT r MarkupM ()
asksHtml f = ReaderT (asks (H.toHtml . f))

userBox :: ReaderT User MarkupM ()
userBox = do
      l dl $ do
        r $ dt "Username"
        l dd (asksHtml username)
        r $ dt "UserId"
        l dd (asksHtml userId)

page :: ReaderT User MarkupM ()
page = do
  l H.docTypeHtml $ do
    r $ H.head $ title "Reader Monad Blaze Example"
    l H.body $ do
      r $ h1 "Hello world"
      userBox
于 2013-12-23T20:42:21.137 回答
0

Blaze 的Markup类型不是转换器,因此不能用于转换ReaderT.

type Markup = MarkupM ()
data MarkupM a

您可以使用该lucid软件包(此处为教程),如下所示:

$ stack build lucid
$ stack exec ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
> :set -XOverloadedStrings -XExtendedDefaultRules
> import Lucid
> import Control.Monad.Trans.Reader
> import Control.Monad.Trans
> runReaderT (renderTextT (do p_ (do title <- lift ask; strong_ (toHtml title)))) "Hi"
"<p><strong>Hi</strong></p>"
> 
于 2018-08-28T13:34:32.400 回答