Lucid "Term" 类型的真正含义
The true meaning of Lucid's "Term" type
我一直在玩 Haskell,尝试使用 Servant 和 Lucid 创建一个非常简单的网站。此刻我走到了舞台"My code works, I have no idea why"。
我尝试创建 Bootstrap 按钮。根据文档,它应该定义为:
<button type="button" class="btn btn-primary">Primary</button>
所以我找到了 Lucid.Html5 文档:https://hackage.haskell.org/package/lucid-2.9.11/docs/Lucid-Html5.html 并计算出了创建按钮的函数:
button_ :: Term arg result => arg -> result
在花了一些时间尝试找出正确的语法后,我想到了这个:
-- correctly replicates the html pasted above
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
通常我会把它称为胜利并专注于其他任务,但对我来说这看起来像是真正的魔法。
文档说 "button_" 是一个接受参数 "arg" 和 returns 泛型值 "result" 的函数。但是,在我的应用程序中 "button_" 显然需要两个参数和 returns "Html ()".
-- f arg arg again ??
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
它必须对 "Term" 类型类做一些事情,但我不确定如何理解它。有人可以帮我弄这个吗 ?我尝试将模块加载到 ghci 并使用“:t”检查类型,但这对我没有太大帮助。
Term
类型类非常方便——我们不需要不同的 term
函数来创建带或不带属性的元素——但可能有点难以理解。
button_
的定义是
-- | @button@ element
button_ :: Term arg result => arg -> result
button_ = term "button"
term
is a method of the Term
类型类,并且具有类型:
term :: Text -> arg -> result
也就是说:你给它元素的名称,一些类型取决于特定实例的参数,它 returns 一些结果,其类型取决于特定实例。但是有哪些实例可用?一共有三个:
Term Text Attribute
-- here, term :: Text -> Text -> Attribute
这个用于创建属性,而不是元素。
Applicative m => Term (HtmlT m a) (HtmlT m a)
-- here, term :: Text -> HtmlT m a -> HtmlT m a
这个用于创建没有属性的元素。我们作为参数传递给 term
的 arg
是代表 children 的 html 的一部分,我们在 return 中得到另一部分 html .
(Applicative m, f ~ HtmlT m a) => Term [Attribute] (f -> HtmlT m a)
-- here, term :: Text -> [Attribute] -> HtmlT m a -> HtmlT m a
这是最令人困惑的一个,也是您的代码中正在使用的一个。这里,arg
是 Attribute
值的列表。这点很清楚。但是 result
是函数的类型!传递属性后,我们剩下 另一个 函数 HtmlT m a
-> HtmlT m a
允许我们提供按钮的内容("Primary" in你的情况)。
f ~ HtmlT m a
是另一个与此答案无关的问题。它只是说 f
等于 HtmlT m a
。那为什么不直接放呢?好吧,在某些情况下,它可以以理想的方式帮助 drive type inference。
我一直在玩 Haskell,尝试使用 Servant 和 Lucid 创建一个非常简单的网站。此刻我走到了舞台"My code works, I have no idea why"。 我尝试创建 Bootstrap 按钮。根据文档,它应该定义为:
<button type="button" class="btn btn-primary">Primary</button>
所以我找到了 Lucid.Html5 文档:https://hackage.haskell.org/package/lucid-2.9.11/docs/Lucid-Html5.html 并计算出了创建按钮的函数:
button_ :: Term arg result => arg -> result
在花了一些时间尝试找出正确的语法后,我想到了这个:
-- correctly replicates the html pasted above
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
通常我会把它称为胜利并专注于其他任务,但对我来说这看起来像是真正的魔法。
文档说 "button_" 是一个接受参数 "arg" 和 returns 泛型值 "result" 的函数。但是,在我的应用程序中 "button_" 显然需要两个参数和 returns "Html ()".
-- f arg arg again ??
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
它必须对 "Term" 类型类做一些事情,但我不确定如何理解它。有人可以帮我弄这个吗 ?我尝试将模块加载到 ghci 并使用“:t”检查类型,但这对我没有太大帮助。
Term
类型类非常方便——我们不需要不同的 term
函数来创建带或不带属性的元素——但可能有点难以理解。
button_
的定义是
-- | @button@ element
button_ :: Term arg result => arg -> result
button_ = term "button"
term
is a method of the Term
类型类,并且具有类型:
term :: Text -> arg -> result
也就是说:你给它元素的名称,一些类型取决于特定实例的参数,它 returns 一些结果,其类型取决于特定实例。但是有哪些实例可用?一共有三个:
Term Text Attribute
-- here, term :: Text -> Text -> Attribute
这个用于创建属性,而不是元素。
Applicative m => Term (HtmlT m a) (HtmlT m a)
-- here, term :: Text -> HtmlT m a -> HtmlT m a
这个用于创建没有属性的元素。我们作为参数传递给 term
的 arg
是代表 children 的 html 的一部分,我们在 return 中得到另一部分 html .
(Applicative m, f ~ HtmlT m a) => Term [Attribute] (f -> HtmlT m a)
-- here, term :: Text -> [Attribute] -> HtmlT m a -> HtmlT m a
这是最令人困惑的一个,也是您的代码中正在使用的一个。这里,arg
是 Attribute
值的列表。这点很清楚。但是 result
是函数的类型!传递属性后,我们剩下 另一个 函数 HtmlT m a
-> HtmlT m a
允许我们提供按钮的内容("Primary" in你的情况)。
f ~ HtmlT m a
是另一个与此答案无关的问题。它只是说 f
等于 HtmlT m a
。那为什么不直接放呢?好吧,在某些情况下,它可以以理想的方式帮助 drive type inference。