Making html fragments with lucid

I would like to make some html fragments with the lucid html dsl. These would simplify bootstraps row and cols

what I have now looks like this

row_ :: Html () -> Html ()
row_ content = do
  div_ [class_ "row"] $ do
    content

col_lg_3_ :: Html () -> Html ()
col_lg_3_ content = do
  div_ [class_ "col-lg-3"] $ do
    content

data HomeView = HomeView

instance ToHtml HomeView where

  toHtml HomeView = do
    h1_ "Home Page"
    row_ $ do
      col_lg_3_ $ do
        p_ "This is content"

  toHtmlRaw = toHtml

However, I get the type error

   • Couldn't match type ‘m’ with ‘Data.Functor.Identity.Identity’
      ‘m’ is a rigid type variable bound by
        the type signature for:
          toHtml :: forall (m :: * -> *). Monad m => HomeView -> HtmlT m ()
        at src/Lib.hs:36:3-8
      Expected type: HtmlT m ()
        Actual type: Html ()
    • In a stmt of a 'do' block:
        row_ $ do col_lg_3_ $ do p_ "This is content"
      In the expression:
        do h1_ "Home Page"
           row_ $ do col_lg_3_ $ do ...
      In an equation for ‘toHtml’:
          toHtml HomeView
            = do h1_ "Home Page"
                 row_ $ do col_lg_3_ $ ...
    • Relevant bindings include
        toHtml :: HomeView -> HtmlT m () (bound at src/Lib.hs:36:3)
   |
38 |     row_ $ do
   |     ^^^^^^^^^...

I don’t really understand what to do next.

2 Likes

Hmm, it looks like row has the type:

row :: Term arg result => arg -> result

and Term is bound by:

class Term arg result | result -> arg

so we need some way to turn the output of row_ into something of type Html. To quote from the term definition:

The second is an arg which is HtmlT m () , in which case the term accepts no attributes and just the children are used for the element. So it looks like the argument is correct but the return type is wrong.

I’m beginning to see why you’re lost, I am too. I’ve turned your example into a gist with imports and a main and whatnot in service of anyone else who wants to help.

Sorry I couldn’t help you more.

In brief, the problem is that your helper functions’ types are too specific.

The required type of toHtml is Monad m => a -> HtmlT m (), polymorphic in m. Both of your helper functions, however, have types Html () -> Html (), or, expanding the type synonym, HtmlT Identity () -> HtmlT Identity (); so m is fixed to Identity, hence the error. Replacing the type signatures with Monad m => HtmlT m () -> HtmlT () fixes it.

1 Like

Thanks to both of you for your help.

Changing the type signature to this worked

row_ :: Monad m => HtmlT m () -> HtmlT m ()
row_ content = do
  div_ [class_ "row"] $ do
    content

col_lg_3_ :: Monad m => HtmlT m () -> HtmlT m ()
col_lg_3_ content = do
  div_ [class_ "col-lg-3"] $ do
    content

Thanks again