我一直在与Haskell合作,尝试使用Servant和Lucid创建一个非常简单的网站。目前,我到达“我的代码有效,我不知道为什么”的阶段。 我尝试创建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”并返回通用类型“ result”的值的函数。但是,在我的应用程序中,“ button_”显然带有两个参数并返回“ Html()”。
-- f arg arg again ??
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
它必须对“ Term”类型类进行某些操作,但是我不确定如何理解它。有人可以帮我弄这个吗 ?我尝试将模块加载到ghci中并使用“:t”检查类型,但这并没有太大帮助。
答案 0 :(得分:4)
Term
类型类非常方便-我们不需要不同的term
函数来创建带有或不带有属性的元素-但可能有点难以理解。
button_
的定义是
-- | @button@ element
button_ :: Term arg result => arg -> result
button_ = term "button"
term :: Text -> arg -> result
也就是说,您给它提供元素的名称,一些其类型取决于特定实例的参数,并返回一些其类型取决于特定实例的结果。但是哪些实例可用?有三个:
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
这是用于创建没有属性的元素的。我们作为参数传递给arg
的{{1}}是代表孩子的html片段,作为回报,我们得到了另一段html。
term
这是最令人困惑的,也是代码中正在使用的那个。这里,(Applicative m, f ~ HtmlT m a) => Term [Attribute] (f -> HtmlT m a)
-- here, term :: Text -> [Attribute] -> HtmlT m a -> HtmlT m a
是Attribute
值的列表。那很清楚。但是arg
是函数的类型!传递属性后,我们剩下的是另一个函数result
-> HtmlT m a
,该函数使我们能够提供按钮的内容(在您的情况下为“主要”)。 / p>
HtmlT m a
是另一个皱纹,与该答案无关。它只是说f ~ HtmlT m a
等于f
。那为什么不直接放呢?好吧,在某些情况下,它可以以理想的方式帮助drive type inference。