Given a simple example like this
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>|]
Is there a builtin mechanism in Yesod which would allow me to do both foo "some text" and foo (glyphicon "pencil")? I've managed to work around this by using a custom typeclass which converts both Text and Widget to Widget
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>|]
but this doesn't feel right, especially since I can't even do ^{foo "hello"} due to ambiguous types, and have to do ^{foo (T.pack "hello")} instead.
Is there a better way of embedding both Text and Widget inside another Widget?
I wouldn't go this route, specifically because of the type inference issue you already discovered. Explicitly having to call toWidget occasionally is probably the best compromise here.