Класс типов Term
очень удобен - нам не нужны разные функции term
для создания элементов с атрибутами или без них, но его может быть немного сложно понять.
Определение button_
- это
-- | @button@ element
button_ :: Term arg result => arg -> result
button_ = term "button"
term
- метод класса типов Term
, имеющий тип:
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
, который мы передаем в качестве аргумента term
, представляет собой некоторый фрагмент html, представляющий дочерние элементы, и мы получаем взамен еще один фрагмент 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
, которая позволяет нам предоставлять содержимое кнопки («Основной» в вашем случае).
f ~ HtmlT m a
- еще одна морщина, которая не имеет отношения к этому ответу. Это просто говорит о том, что f
равно HtmlT m a
. Почему бы не поставить это прямо тогда? Ну, в некоторых случаях это может помочь вывод типа привода желаемым образом.