I've been playing with Haskell, trying to create a very simple website using Servant and Lucid. At the moment I reached the stage "My code works, I have no idea why". I tried creating Bootstrap button. According the the doc, it should be defined as:
<button type="button" class="btn btn-primary">Primary</button>
So I found Lucid.Html5 doc: https://hackage.haskell.org/package/lucid-2.9.11/docs/Lucid-Html5.html and worked out the function that creates a button:
button_ :: Term arg result => arg -> result
After spending some time trying to work out the correct syntax, I came up with this:
-- correctly replicates the html pasted above
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
Typically I would have called it a victory and focused on other tasks, but this one looks like a true piece of magic to me.
The doc says "button_" is a function that takes an argument "arg" and returns a value of a generic type "result". However, in my application "button_" clearly takes two arguments and returns "Html ()".
-- f                       arg                     arg again ??
button_ [type_ "button", class_ "btn btn-primary"] "Primary"
It must do something with the "Term" typeclass, but I'm not sure how to understand it. Can someone help me with this ? I tried loading the module into ghci and inspecting types with ":t", but that didn't help me too much.
 
                        
The
Termtypeclass is very convenient—we don't need differenttermfunctions for creating elements with or without attributes—but can be a bit difficult to understand.The definition of
button_istermis a method of theTermtypeclass, and has type:That is: you give it the name of the element, some argument whose type depends on the particular instance, and it returns some result whose type depends on the particular instance. But what instances are available? There are three:
This one is for creating attributes, not elements.
This one is for creating elements without attributes. The
argwe pass as argument totermis some piece of html representing the children, and we get another piece of html in return.This one is the most confusing, and the one that is being used in your code. Here,
argis a list ofAttributevalues. That much is clear. Butresultis the type of a function! After passing the attributes, we are left with another functionHtmlT m a->HtmlT m awhich allows us to supply the contents of the button ("Primary" in your case).The
f ~ HtmlT m ais another wrinkle that isn't really relevant for this answer. It simply says thatfis equal toHtmlT m a. Why not put it directly then? Well, in certain cases it can help drive type inference in desirable ways.