0

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?

Jakub Arnold
  • 85,596
  • 89
  • 230
  • 327

1 Answers1

1

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.

Michael Snoyman
  • 31,100
  • 3
  • 48
  • 77