Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting with Text.XHtml

I have the following code to generate a blank html page with a series of divs with id's and classes in Haskell using the Text.XHtml.Strict library:

module Main where

import Text.XHtml.Strict
import Text.Printf


page :: Html
page = pHeader +++ pTop +++ pBody +++ pFooter

pHeader :: Html
pHeader = header << thetitle << "Page title" 

pTop :: Html
pTop = (dC "header") << (dI "title") 

pFooter :: Html
pFooter = (dC "footer") << (dI "foottext")

pBody :: Html
pBody = body << (dC "main") << (dI "window") << (dI "content")

dC :: String -> Html
dC x = (thediv noHtml)! [theclass x]

dI :: String -> Html
dI x = (thediv noHtml) ! [identifier x]

main :: IO ()
main = do
    printf $ prettyHtml $ page

The functions dC and dI should make an empty with a class or id respectively. In the interpreter these functions work fine when concatenating, as in:

 printf $ prettyHtmlFragment $ dC "1" +++ dC "2"
<div class="1">
</div>
<div class="2">
</div>

But not when I try to nest them using << instead of +++, I get an error:

<interactive>:1:28:
    Couldn't match expected type `Html -> b'
           against inferred type `Html'

This is what I think the cause of the problem in the main part of the code is, but I don't know how to fix it. Any ideas?

like image 631
Jonno_FTW Avatar asked May 24 '26 14:05

Jonno_FTW


2 Answers

Just take out the nohtml parts, and change the signatures:

dC :: String -> Html -> Html
dC x = thediv ! [theclass x]

dI :: String -> Html -> Html
dI x = thediv ! [identifier x]

The ! operator can add attributes not only to an Html object, but also to a function that returns Html. thediv is a function that takes Html and returns it wrapped in a <div> element. By applying ! to it, you create a function that takes Html and wraps a <div class="…"> (or id="…") around it.

> :type thediv
thediv :: Html -> Html

> let dC c = thediv ! [theclass c]
> let dI i = thediv ! [identifier i]

> :type dC
dC :: String -> Html -> Html
> :type dI
dI :: String -> Html -> Html

> putStr $ prettyHtmlFragment $ body << dC "main" << dI "window" << dI "content" << "Hi"
<body>
   <div class="main">
      <div id="window">
         <div id="content">
            Hi
         </div>
      </div>
   </div>
</body>

Note that you don't need the extra parenthesis.

like image 162
MtnViewMark Avatar answered May 27 '26 13:05

MtnViewMark


dC and cI can't nest because they're defined to be empty. You need to leave a hole that the nested piece will go into. The hole is expressed by parameterizing it:

dC classx child = (thediv child)! [theclass classx] 
dI x y = (thediv y) ! [identifier x] 

likewise for body:

pBody x = body << (dC "main") << (dI "window") << (dI "content" x) 
like image 20
ja. Avatar answered May 27 '26 13:05

ja.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!