我刚刚开始使用Yesod,虽然我已经可以获得一些有趣的结果,但我很难理解其中的一些类型(可能是因为我不熟悉模板Haskell)。
将一个哈姆雷特片段传递给通常方式函数的defaultLayout函数是通过toWidget函数。因此,按照下面ham1和ham2的定义,defaultLayout中的适当指令分别是toWidget ham1和ham2。
我的问题:在下面的(工作)代码中为什么指令toWidget ham2编译,而它是一个与ham1非常不同的动物?我猜这意味着ham1的类型(ham1 :: t -> Text.Blaze.Internal.Markup (*))和ham2的类型(ham2 :: Widget)都是ToWidget类的实例,但在我阅读类实例定义时,这并不是完全显而易见的。
(*),如果有人能告诉我是否有比t -> Text.Blaze.Internal.Markup更好的同义词,那就太好了。
代码:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import Yesod
import Text.Blaze.Internal (Markup)
data App = App
instance Yesod App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
getHomeR :: Handler Html
getHomeR = defaultLayout $ do
setTitle "Some Title"
toWidget ham1 -- usual way to produce a Widget from hamlet snippet
toWidget ham2 -- ??
ham2 -- already of type Widget
ham1 :: t -> Text.Blaze.Internal.Markup -- explicit signature for reference only
ham1 = [hamlet|
<h1> 1) Hello
<h2> World!
|]
ham2 :: Widget
ham2 =
toWidget [hamlet|
<h1> 2) Hello
<h2> World!
|]
main :: IO ()
main = do
warp 3000 App产出:

发布于 2016-01-05 11:24:38
我不太确定你问的是什么,所以我只想解释一下它是如何工作的,我希望它是相关的。
defaultLayout使用一个小部件将其放入well…中。默认布局。因此,您的do-block以单一方式组合了小部件。要传递类型检查器,do-block中的每一行都应该是Widget a (或WidgetT App IO a,是站点的数据类型为App)。ToWidget的实例是可以转换为小部件的东西。Widget是这个类型类的实例,也是render -> Html类的实例。考虑到Html是Text.Blaze.Internal.Markup的同义词,您的ham1是传递给toWidget的最佳候选,参见源代码:
instance render ~ RY site => ToWidget site (render -> Html) where
toWidget x = …(~)添加了额外的约束,它告诉类型检查器(在它已经选择了这个实例之后),按照render必须具有RY site类型的方式。site是一种幻影类型,它确保系统的不同部分属于同一个站点,如果使用脚手架,通常是App。RY site使用另一个类型同义词RY传递它的site变量,它的结果如下所示:
Route App -> [(Text, Text)] -> Text这是ham1使用的参数类型。
因此,这些实例允许您将不同的东西转换为小部件,包括类似于hamlet准商生成的函数,这里没有魔力。
https://stackoverflow.com/questions/34609651
复制相似问题