Haskell 如何在defaultLayout引用的小部件/小村庄中执行IO?
我对Yesod是个新手,似乎对小部件、处理程序、哈姆雷特、WHamlets以及你所拥有的东西完全迷茫了!以下是我想做的:Haskell 如何在defaultLayout引用的小部件/小村庄中执行IO?,haskell,yesod,shakespeare-text,Haskell,Yesod,Shakespeare Text,我对Yesod是个新手,似乎对小部件、处理程序、哈姆雷特、WHamlets以及你所拥有的东西完全迷茫了!以下是我想做的: 我网站上的每个页面都需要一个导航栏,这让我相信实现这一点的正确位置应该是defaultLayout 现在,这个导航栏需要显示从IO操作获得的一些信息(更具体地说,是一个RPC调用提供了这些数据) 因此,我尝试在Foundation.hs中编写以下函数(代码布局是基本的yesod-sqlitescaffolding模板): 以下是默认布局包装器。hamlet看起来像: &l
- 我网站上的每个页面都需要一个导航栏,这让我相信实现这一点的正确位置应该是
defaultLayout
- 现在,这个导航栏需要显示从IO操作获得的一些信息(更具体地说,是一个RPC调用提供了这些数据)
Foundation.hs
中编写以下函数(代码布局是基本的yesod-sqlite
scaffolding模板):
以下是默认布局包装器。hamlet
看起来像:
<nav .navbar .navbar-default>
<div .container-fluid>
<p .navbar-right .navbar-text>
<span>
#{A2.glDownloadSpeed globalStat}
<i .glyphicon .glyphicon-arrow-down>
<span>
#{A2.glUploadSpeed globalStat}
<i .glyphicon .glyphicon-arrow-up>
<span .label .label-success>
On-the-watch
<!-- SNIP -->
<body>
<div class="container">
<header>
^{nav}
<div id="main" role="main">
^{pageBody pc}
<!-- SNIP -->
defaultLayout widget = do
master <- getYesod
mmsg <- getMessage
pc <- widgetToPageContent $ do
addStylesheet $ StaticR css_bootstrap_css
$(widgetFile "default-layout")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
但是,代码拒绝编译,并出现一个又一个类型错误。我尝试了很多组合,包括hametFile
、whamletFile
、handerwidget
、liftIO
,甚至将导航功能放在defaultLayout
中,但似乎没有任何效果。据我所知,我当前的代码应该编译,但我显然不了解YesSOD核心类型是如何工作的
我怎样才能让它工作?更重要的是,我误解了什么概念
编辑1:
已尝试将nav
功能修改为以下内容:
nav :: Handler Html
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
编辑2:
尝试将nav
的类型签名更改为:
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
编辑3:
以下是来自-ddump拼接的相关片段:
\ _render_a28TE
-> do { asHtmlUrl (pageHead pc) _render_a28TE;
id ((Text.Blaze.Internal.preEscapedText . Data.Text.pack) "\n");
asHtmlUrl (pageBody pc) _render_a28TE;
id ((Text.Blaze.Internal.preEscapedText . Data.Text.pack) "\n");
asHtmlUrl testWidget2 _render_a28TE }
(pageHead pc)
和(pageBody pc)
的类型是HtmlUrl(Route App)
请查看对的答案。基本上,您不能在模板中执行IO
还要注意的是,defaultLayout
的类型是GHandler…
,GHandler
是an,因此您可以使用liftIO
在defaultLayout
中执行IO
我会尝试:
defaultLayout = do
...
globalStat <- liftIO $ handlerToWidget $ A2.getGlobalStat NWT.ariaRPCUrl
uploadSpeed <- liftIO $ A2.glUploadSpeed globalStat
downloadSpeed <- liftIO $ A2.glDownloadSpeed globalStat
...
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
而nav
会变成:
nav uploadSpeed downloadSpeed = $(whamletFile "templates/navbar.hamlet)
因此,基本思想是:
- 使用
liftIO
- 将子模板所需的数据作为函数参数传递
更新
要进行模拟,您需要像这样编写navbar
:
navbar :: Widget
navbar = do
globalStat <- liftIO A2.getGlobalStat NWT.ariaRPCUrl
downloadSpeed <- liftIO A2.glDownloadSpeed globalStat
uploadSpeed <- liftIO A.glUploadSpeed
$(whamletFile "templates/navbar.hamlet)
navbar::Widget
navbar=do
globalStat以下是我如何让它工作的。实际上,我面临着两个不同的问题:
- 在小部件中执行IO
- 引用
默认布局包装文件中的小部件
以下是在小部件内执行IO的解决方案:
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(whamletFile "templates/navbar.hamlet")
默认布局包装器。哈姆雷特:将一些HTML元素从此文件移动到默认布局
:
<!-- SNIP -->
<body>
<div class="container">
^{pageBody pc}
<!-- SNIP -->
^{pageBody pc}
谢谢您的回答@ErikR。你会怎么说?我想做的不是很相似吗?谢谢,埃里克。这对我来说仍然不起作用,但至少我已经取得了一些进展。您建议使用handlerToWidget$liftIO
已使nav
函数的类型更简单,即nav::(MonadIO m)=>WidgetT site m()
。然而,这让我想知道为什么首先需要liftIO
handlerToWidget
。为什么liftIO
无法将IO操作直接提升到WidgetT站点m()
转换器堆栈?我的直觉是正确的。实际上并不需要handlerToWidget
。因为我没有给出顶级类型声明,liftIO
不知道将IO操作提升到哪个monad。只需添加nav::Widget
作为顶级类型声明,即可使nav
函数在编译时不使用handlerToWidget
。谢谢ErikR。我已经设法在处理程序操作中执行IO,但不是在我所针对的原始代码中。我在您的工作示例中重现了相同的错误,请注意defaultLayout
实现(这是yesod sqlite scaffold提供的)。一旦defaultLayout
更改为此定义,lpaste wrapper.hamlet
就无法调用^{testWidget2}
或^{testWidget}
可能是-ddump拼接的输出有帮助吗?请看我的最新编辑。编辑我的问题以基于liftIO
方法发布新的代码片段。现在,问题似乎是^{nav}
默认布局包装器
模板中的^{nav}
用法似乎组合不好。
nav uploadSpeed downloadSpeed = $(whamletFile "templates/navbar.hamlet)
navbar :: Widget
navbar = do
globalStat <- liftIO A2.getGlobalStat NWT.ariaRPCUrl
downloadSpeed <- liftIO A2.glDownloadSpeed globalStat
uploadSpeed <- liftIO A.glUploadSpeed
$(whamletFile "templates/navbar.hamlet)
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(whamletFile "templates/navbar.hamlet")
<div .container>
<header>
^{nav}
<div #main role="main">
$maybe msg <- mmsg
<div #message>#{msg}
^{widget}
<!-- SNIP -->
<body>
<div class="container">
^{pageBody pc}
<!-- SNIP -->