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

这个用于创建没有属性的元素。我们作为参数传递给 termarg 是代表 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

这是最令人困惑的一个,也是您的代码中正在使用的一个。这里,argAttribute 值的列表。这点很清楚。但是 result 是函数的类型!传递属性后,我们剩下 另一个 函数 HtmlT m a -> HtmlT m a 允许我们提供按钮的内容("Primary" in你的情况)。

f ~ HtmlT m a 是另一个与此答案无关的问题。它只是说 f 等于 HtmlT m a。那为什么不直接放呢?好吧,在某些情况下,它可以以理想的方式帮助 drive type inference