dan*_*dan 5 haskell blaze-html
该BlazeHtml教程建议使用现实世界的模板与BlazeHtml一个Reader单子,但没有说明如何应该这样做.我试着遵循这个建议.结果让我感到困惑.
为了说明,假设我有一个简单的用户类型,我想使用单独的函数编写我的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
Run Code Online (Sandbox Code Playgroud)
将此与我不使用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
Run Code Online (Sandbox Code Playgroud)
因此,我很难看到Reader Monad如何在实际用例中实际收紧模板代码.我错过了什么吗?
如果你扩展你的类型,你会看到
page :: Reader User Html
:: Reader User Markup
:: Reader User (MarkupM ())
Run Code Online (Sandbox Code Playgroud)
因此,通过使用变换器堆栈可以获得更多的杠杆作用.
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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
792 次 |
最近记录: |