Как я могу встроить текст и виджет в другой виджет в Yesod?

Учитывая простой пример, подобный этому

glyphicon :: Text -> Widget
glyphicon name = toWidget [hamlet|<span class="glyphicon glyphicon-#{name}">|]

foo :: ToMarkup a => a -> Widget
foo content = toWidget [hamlet|<div class="foo">#{content}</div>|]

Есть ли в Yesod встроенный механизм, который позволил бы мне выполнять как foo "some text", так и foo (glyphicon "pencil")? Мне удалось обойти это, используя собственный класс типов, который преобразует как текст, так и виджет в виджет.

class MakeWidget a where
  makeWidget :: a -> Widget

instance MakeWidget Widget where
  makeWidget = id

instance MakeWidget Text where
  makeWidget x = toWidget [hamlet|#{x}|]

glyphicon :: Text -> Widget
glyphicon name = toWidget [hamlet|<span class="glyphicon glyphicon-#{name}">|]

foo :: MakeWidget a => a -> Widget
foo content = toWidget [whamlet|<div class="foo">^{makeWidget content}</div>|]

но это кажется неправильным, тем более что я даже не могу сделать ^{foo "hello"} из-за неоднозначных типов и вместо этого должен сделать ^{foo (T.pack "hello")}.

Есть ли лучший способ встроить Text и Widget в другой Widget?


person Jakub Arnold    schedule 14.02.2015    source источник


Ответы (1)


Я бы не пошел по этому пути, особенно из-за проблемы с выводом типа, которую вы уже обнаружили. Явный вызов toWidget время от времени, вероятно, является лучшим компромиссом.

person Michael Snoyman    schedule 14.02.2015