我刚开始玩Yesod,虽然我已经可以得到一些有趣的结果,但我正在努力清楚地了解它的一些类型(可能是因为我不熟悉Template Haskell)。
将一个hamlet片段传递给defaultLayout函数的usual way是通过toWidget函数。因此,遵循下面的ham1和ham2的定义,defaultLayout中的正确指令分别是toWidget ham1
和ham2
。
我的问题:在下面的(工作)代码中,为什么指令toWidget ham2
会编译,而它与ham1的动物却完全不同?我猜这意味着ham1的类型(ham1 :: t -> Text.Blaze.Internal.Markup
(*))和ham2的类型(ham2 :: Widget
)都是ToWidget类的实例但在阅读class' instance definitions时,这对我来说并不完全明显。
(*)此外,如果有人可以告诉我是否有更好的"那么它会很棒。为ham1键入同义词而不是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
输出:
答案 0 :(得分:2)
我不完全确定被问到了什么,所以我只是解释一下它是如何工作的, 我希望它具有相关性。
defaultLayout
将小部件放入井中...默认布局。因此你的
do
- 块单独组合小部件。传递类型检查器,每行都在
do
- 阻止类型应为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
准引号产生的函数,没有魔法
这里。