3

I apologize for the bad title, but I don't quite know how to summarize this.

I'm a Haskell beginner, making a website in Haskell (Hakyll) using templates in Blaze-HTML, which uses do notation to make HTML. Here's part of my template:

defaultTemplateRaw :: Html
defaultTemplateRaw = html $ do
    H.head $ do
        meta ! httpEquiv "Content-Type" ! content "text/html; charset=UTF-8"
        H.title "My Hakyll Blog - $title$"
        link ! rel "stylesheet" ! type_ "text/css" ! href "/css/main.css"
        link ! rel "stylesheet" ! type_ "text/css" ! href "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
        link ! rel "stylesheet" ! type_ "text/css" ! href "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" 

Now let's say I wanted to be DRY here, so I wouldn't have all the links, just a list of URLs in some kind of list comprehension. How would I do that?

gallais
  • 11,823
  • 2
  • 30
  • 63
Jonathan
  • 10,571
  • 13
  • 67
  • 103

1 Answers1

4

You can use mapM_ here:

thelinks :: [AttributeValue]
thelinks = ["list", "of", "hrefs"]

defaultTemplateRaw :: Html
defaultTemplateRaw = html $ do
    H.head $ do
        meta ! httpEquiv "Content-Type" ! content "text/html; charset=UTF-8"
        H.title "My Hakyll Blog - $title$"
        mapM_ ((link ! rel "stylesheet" ! type_ "text/css" !) . href) thelinks

So here we use mapM_ :: Monad m => (a -> m b) -> t a -> m () to process the monadic function ((link ! rel "stylesheet" ! type_ "text/css" !) . href) for every element of the list thelinks.

We construct the function by using operator section, so:

(link ! rel "stylesheet" ! type_ "text/css" !)

is equivalent with:

\x -> link ! rel "stylesheet" ! type_ "text/css" ! x

But we can not directly pass an AttributeValue as x to that function: we need to use the href attribute, we do so by using . href, thus thus means that:

  (link ! rel "stylesheet" ! type_ "text/css" !) . href
-----------------------------------------------------------------------
= (\x -> link ! rel "stylesheet" ! type_ "text/css" ! x) . href
-----------------------------------------------------------------------
= \y -> (\x -> link ! rel "stylesheet" ! type_ "text/css" ! x) (href y)
-----------------------------------------------------------------------
= \y -> (link ! rel "stylesheet" ! type_ "text/css" ! (href y))

So it is a more syntactically convenient way to call the href function on the item of the list, and that result in the structure of link ! ....

For the given sample list, this produces:

Main L R> putStrLn $ L.unpack $ R.renderHtml defaultTemplateRaw
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>My Hakyll Blog - $title$</title><link rel="stylesheet" type="text/css" href="list"><link rel="stylesheet" type="text/css" href="of"><link rel="stylesheet" type="text/css" href="hrefs"></head></html>
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555